9
9
10
10
import { withCancellation } from './concurrency' ;
11
11
import { StateStore } from './store' ;
12
- import type { MessageResponse , Attachment , EventTypes , ExtendableGenerics } from './types' ;
12
+ import type { MessageResponse , Attachment , EventTypes , ExtendableGenerics , UpdateMessageAPIResponse } from './types' ;
13
13
import type { StreamChat } from './client' ;
14
14
import type { Unsubscribe } from './store' ;
15
15
16
16
// type Unsubscribe = () => void;
17
17
type WatchLocation = ( handler : ( value : { latitude : number ; longitude : number } ) => void ) => Unsubscribe ;
18
- type SerializeAndStore = ( state : MessageResponse [ ] , userId : string ) => void ;
19
- type RetrieveAndDeserialize = ( userId : string ) => MessageResponse [ ] ;
18
+ type SerializeAndStore < SCG extends ExtendableGenerics > = ( state : MessageResponse < SCG > [ ] , userId : string ) => void ;
19
+ type RetrieveAndDeserialize < SCG extends ExtendableGenerics > = ( userId : string ) => MessageResponse < SCG > [ ] ;
20
20
21
- export type LiveLocationManagerState = {
21
+ export type LiveLocationManagerState < SCG extends ExtendableGenerics > = {
22
22
ready : boolean ;
23
- targetMessages : MessageResponse [ ] ;
23
+ targetMessages : MessageResponse < SCG > [ ] ;
24
24
} ;
25
25
26
26
// if (message.cid && this.messagesByChannelConfId[message.cid]) {
@@ -87,39 +87,55 @@ export type LiveLocationManagerState = {
87
87
// }
88
88
89
89
function isValidLiveLocationAttachment ( attachment ?: Attachment ) {
90
- if ( ! attachment || typeof attachment . end_time !== 'string' || attachment . stopped_sharing ) return false ;
90
+ if ( ! attachment || attachment . type !== 'live_location' || attachment . stopped_sharing ) {
91
+ return false ;
92
+ }
93
+
94
+ // If end_time has been defined, consider it
95
+ if ( typeof attachment . end_time === 'string' ) {
96
+ const endTimeTimestamp = new Date ( attachment . end_time ) . getTime ( ) ;
91
97
92
- const endTimeTimestamp = new Date ( attachment . end_time ) . getTime ( ) ;
98
+ if ( Number . isNaN ( endTimeTimestamp ) ) return false ;
93
99
94
- if ( Number . isNaN ( endTimeTimestamp ) ) return false ;
100
+ const nowTimestamp = Date . now ( ) ;
95
101
96
- const nowTimestamp = Date . now ( ) ;
102
+ return nowTimestamp < endTimeTimestamp ;
103
+ }
97
104
98
- return attachment && attachment . type === 'live_location' && endTimeTimestamp > nowTimestamp ;
105
+ return true ;
106
+ }
107
+
108
+ function isValidLiveLocationMessage ( message ?: MessageResponse ) {
109
+ if ( ! message || message . type === 'deleted' ) return false ;
110
+
111
+ const [ attachment ] = message . attachments ?? [ ] ;
112
+
113
+ return isValidLiveLocationAttachment ( attachment ) ;
99
114
}
100
115
101
116
export type LiveLocationManagerConstructorParameters < SCG extends ExtendableGenerics > = {
102
117
client : StreamChat < SCG > ;
103
118
watchLocation : WatchLocation ;
104
- retrieveAndDeserialize ?: RetrieveAndDeserialize ;
105
- serializeAndStore ?: SerializeAndStore ;
119
+ retrieveAndDeserialize ?: RetrieveAndDeserialize < SCG > ;
120
+ serializeAndStore ?: SerializeAndStore < SCG > ;
106
121
} ;
107
122
108
- const MIN_THROTTLE_TIMEOUT = 1000 ;
123
+ // Hard-coded minimal throttle timeout
124
+ const MIN_THROTTLE_TIMEOUT = 3000 ;
109
125
110
126
export class LiveLocationManager < SCG extends ExtendableGenerics > {
111
- public state : StateStore < LiveLocationManagerState > ;
127
+ public state : StateStore < LiveLocationManagerState < SCG > > ;
112
128
private client : StreamChat < SCG > ;
113
129
private unsubscribeFunctions : Set < ( ) => void > = new Set ( ) ;
114
- private serializeAndStore : SerializeAndStore ;
130
+ private serializeAndStore : SerializeAndStore < SCG > ;
115
131
private watchLocation : WatchLocation ;
116
132
private messagesByChannelConfIdGetterCache : {
117
133
calculated : { [ key : string ] : [ MessageResponse , number ] } ;
118
- targetMessages : LiveLocationManagerState [ 'targetMessages' ] ;
134
+ targetMessages : LiveLocationManagerState < SCG > [ 'targetMessages' ] ;
119
135
} ;
120
136
private messagesByIdGetterCache : {
121
137
calculated : { [ key : string ] : [ MessageResponse , number ] } ;
122
- targetMessages : LiveLocationManagerState [ 'targetMessages' ] ;
138
+ targetMessages : LiveLocationManagerState < SCG > [ 'targetMessages' ] ;
123
139
} ;
124
140
125
141
static symbol = Symbol ( LiveLocationManager . name ) ;
@@ -144,7 +160,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
144
160
145
161
const retreivedTargetMessages = retrieveAndDeserialize ( client . userID ! ) ;
146
162
147
- this . state = new StateStore < LiveLocationManagerState > ( {
163
+ this . state = new StateStore < LiveLocationManagerState < SCG > > ( {
148
164
targetMessages : retreivedTargetMessages ,
149
165
// If there are no messages to validate, the manager is considered "ready"
150
166
ready : retreivedTargetMessages . length === 0 ,
@@ -204,7 +220,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
204
220
let unsubscribeWatchLocation : null | ( ( ) => void ) = null ;
205
221
206
222
// Subscribe to location updates only if there are relevant messages to
207
- // update, no need for the location watcher to active/instantiated otherwise
223
+ // update, no need for the location watcher to be active/instantiated otherwise
208
224
const unsubscribe = this . state . subscribeWithSelector (
209
225
( { targetMessages } ) => ( { targetMessages } ) ,
210
226
( { targetMessages } ) => {
@@ -239,39 +255,29 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
239
255
nextWatcherCallTimestamp = Date . now ( ) + MIN_THROTTLE_TIMEOUT ;
240
256
241
257
withCancellation ( LiveLocationManager . symbol , async ( ) => {
242
- const promises : Promise < void > [ ] = [ ] ;
258
+ const promises : Promise < UpdateMessageAPIResponse < SCG > > [ ] = [ ] ;
243
259
const { ready } = this . state . getLatestValue ( ) ;
244
260
245
261
if ( ! ready ) {
246
262
await this . recoverAndValidateMessages ( ) ;
247
263
}
248
264
249
265
const { targetMessages } = this . state . getLatestValue ( ) ;
250
- // if validator removes messages, we need to check
266
+ // If validator removes messages, we need to check
251
267
if ( ! targetMessages . length ) return ;
252
268
253
269
for ( const message of targetMessages ) {
254
- const [ attachment ] = message . attachments ?? [ ] ;
255
-
256
- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
270
+ if ( ! isValidLiveLocationMessage ( message ) ) {
257
271
this . unregisterMessage ( message ) ;
258
272
continue ;
259
273
}
260
274
261
- // TODO: client.updateLiveLocation instead
262
- const promise = this . client
263
- . partialUpdateMessage ( message . id , {
264
- // @ts -expect-error valid update
265
- set : { attachments : [ { ...attachment , latitude, longitude } ] } ,
266
- } )
267
- // TODO: change this this
268
- . then ( ( v ) => console . log ( v ) ) ;
275
+ const promise = this . client . updateLiveLocation ( message , { latitude, longitude } ) ;
269
276
270
277
promises . push ( promise ) ;
271
278
}
272
279
273
- const values = await Promise . allSettled ( promises ) ;
274
- console . log ( values ) ;
280
+ await Promise . allSettled ( promises ) ;
275
281
// TODO: handle values (remove failed - based on specific error code), keep re-trying others
276
282
} ) ;
277
283
} ) ;
@@ -298,29 +304,25 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
298
304
for ( const result of response . results ) {
299
305
const { message } = result ;
300
306
301
- const [ attachment ] = message . attachments ?? [ ] ;
302
-
303
- if ( isValidLiveLocationAttachment ( attachment ) ) {
307
+ if ( isValidLiveLocationMessage ( message ) ) {
304
308
newTargetMessages . push ( message ) ;
305
309
}
306
310
}
307
311
308
312
this . state . partialNext ( { ready : true , targetMessages : newTargetMessages } ) ;
309
313
}
310
314
311
- private registerMessage ( message : MessageResponse ) {
315
+ private registerMessage ( message : MessageResponse < SCG > ) {
312
316
if ( ! this . client . userID || message ?. user ?. id !== this . client . userID ) return ;
313
317
314
- const [ attachment ] = message . attachments ?? [ ] ;
315
-
316
- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
318
+ if ( ! isValidLiveLocationMessage ( message ) ) {
317
319
return ;
318
320
}
319
321
320
322
this . state . next ( ( currentValue ) => ( { ...currentValue , targetMessages : [ ...currentValue . targetMessages , message ] } ) ) ;
321
323
}
322
324
323
- private updateRegisteredMessage ( message : MessageResponse ) {
325
+ private updateRegisteredMessage ( message : MessageResponse < SCG > ) {
324
326
if ( ! this . client . userID || message ?. user ?. id !== this . client . userID ) return ;
325
327
326
328
const [ , targetMessageIndex ] = this . messagesById [ message . id ] ;
@@ -381,9 +383,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
381
383
382
384
if ( ! localMessage ) return ;
383
385
384
- const [ attachment ] = event . message . attachments ?? [ ] ;
385
-
386
- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
386
+ if ( ! isValidLiveLocationMessage ( event . message ) ) {
387
387
this . unregisterMessage ( event . message ) ;
388
388
} else {
389
389
this . updateRegisteredMessage ( event . message ) ;
0 commit comments