99
1010import { withCancellation } from './concurrency' ;
1111import { StateStore } from './store' ;
12- import type { MessageResponse , Attachment , EventTypes , ExtendableGenerics } from './types' ;
12+ import type { MessageResponse , Attachment , EventTypes , ExtendableGenerics , UpdateMessageAPIResponse } from './types' ;
1313import type { StreamChat } from './client' ;
1414import type { Unsubscribe } from './store' ;
1515
1616// type Unsubscribe = () => void;
1717type 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 > [ ] ;
2020
21- export type LiveLocationManagerState = {
21+ export type LiveLocationManagerState < SCG extends ExtendableGenerics > = {
2222 ready : boolean ;
23- targetMessages : MessageResponse [ ] ;
23+ targetMessages : MessageResponse < SCG > [ ] ;
2424} ;
2525
2626// if (message.cid && this.messagesByChannelConfId[message.cid]) {
@@ -87,39 +87,55 @@ export type LiveLocationManagerState = {
8787// }
8888
8989function 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 ( ) ;
9197
92- const endTimeTimestamp = new Date ( attachment . end_time ) . getTime ( ) ;
98+ if ( Number . isNaN ( endTimeTimestamp ) ) return false ;
9399
94- if ( Number . isNaN ( endTimeTimestamp ) ) return false ;
100+ const nowTimestamp = Date . now ( ) ;
95101
96- const nowTimestamp = Date . now ( ) ;
102+ return nowTimestamp < endTimeTimestamp ;
103+ }
97104
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 ) ;
99114}
100115
101116export type LiveLocationManagerConstructorParameters < SCG extends ExtendableGenerics > = {
102117 client : StreamChat < SCG > ;
103118 watchLocation : WatchLocation ;
104- retrieveAndDeserialize ?: RetrieveAndDeserialize ;
105- serializeAndStore ?: SerializeAndStore ;
119+ retrieveAndDeserialize ?: RetrieveAndDeserialize < SCG > ;
120+ serializeAndStore ?: SerializeAndStore < SCG > ;
106121} ;
107122
108- const MIN_THROTTLE_TIMEOUT = 1000 ;
123+ // Hard-coded minimal throttle timeout
124+ const MIN_THROTTLE_TIMEOUT = 3000 ;
109125
110126export class LiveLocationManager < SCG extends ExtendableGenerics > {
111- public state : StateStore < LiveLocationManagerState > ;
127+ public state : StateStore < LiveLocationManagerState < SCG > > ;
112128 private client : StreamChat < SCG > ;
113129 private unsubscribeFunctions : Set < ( ) => void > = new Set ( ) ;
114- private serializeAndStore : SerializeAndStore ;
130+ private serializeAndStore : SerializeAndStore < SCG > ;
115131 private watchLocation : WatchLocation ;
116132 private messagesByChannelConfIdGetterCache : {
117133 calculated : { [ key : string ] : [ MessageResponse , number ] } ;
118- targetMessages : LiveLocationManagerState [ 'targetMessages' ] ;
134+ targetMessages : LiveLocationManagerState < SCG > [ 'targetMessages' ] ;
119135 } ;
120136 private messagesByIdGetterCache : {
121137 calculated : { [ key : string ] : [ MessageResponse , number ] } ;
122- targetMessages : LiveLocationManagerState [ 'targetMessages' ] ;
138+ targetMessages : LiveLocationManagerState < SCG > [ 'targetMessages' ] ;
123139 } ;
124140
125141 static symbol = Symbol ( LiveLocationManager . name ) ;
@@ -144,7 +160,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
144160
145161 const retreivedTargetMessages = retrieveAndDeserialize ( client . userID ! ) ;
146162
147- this . state = new StateStore < LiveLocationManagerState > ( {
163+ this . state = new StateStore < LiveLocationManagerState < SCG > > ( {
148164 targetMessages : retreivedTargetMessages ,
149165 // If there are no messages to validate, the manager is considered "ready"
150166 ready : retreivedTargetMessages . length === 0 ,
@@ -204,7 +220,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
204220 let unsubscribeWatchLocation : null | ( ( ) => void ) = null ;
205221
206222 // 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
208224 const unsubscribe = this . state . subscribeWithSelector (
209225 ( { targetMessages } ) => ( { targetMessages } ) ,
210226 ( { targetMessages } ) => {
@@ -239,39 +255,29 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
239255 nextWatcherCallTimestamp = Date . now ( ) + MIN_THROTTLE_TIMEOUT ;
240256
241257 withCancellation ( LiveLocationManager . symbol , async ( ) => {
242- const promises : Promise < void > [ ] = [ ] ;
258+ const promises : Promise < UpdateMessageAPIResponse < SCG > > [ ] = [ ] ;
243259 const { ready } = this . state . getLatestValue ( ) ;
244260
245261 if ( ! ready ) {
246262 await this . recoverAndValidateMessages ( ) ;
247263 }
248264
249265 const { targetMessages } = this . state . getLatestValue ( ) ;
250- // if validator removes messages, we need to check
266+ // If validator removes messages, we need to check
251267 if ( ! targetMessages . length ) return ;
252268
253269 for ( const message of targetMessages ) {
254- const [ attachment ] = message . attachments ?? [ ] ;
255-
256- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
270+ if ( ! isValidLiveLocationMessage ( message ) ) {
257271 this . unregisterMessage ( message ) ;
258272 continue ;
259273 }
260274
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 } ) ;
269276
270277 promises . push ( promise ) ;
271278 }
272279
273- const values = await Promise . allSettled ( promises ) ;
274- console . log ( values ) ;
280+ await Promise . allSettled ( promises ) ;
275281 // TODO: handle values (remove failed - based on specific error code), keep re-trying others
276282 } ) ;
277283 } ) ;
@@ -298,29 +304,25 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
298304 for ( const result of response . results ) {
299305 const { message } = result ;
300306
301- const [ attachment ] = message . attachments ?? [ ] ;
302-
303- if ( isValidLiveLocationAttachment ( attachment ) ) {
307+ if ( isValidLiveLocationMessage ( message ) ) {
304308 newTargetMessages . push ( message ) ;
305309 }
306310 }
307311
308312 this . state . partialNext ( { ready : true , targetMessages : newTargetMessages } ) ;
309313 }
310314
311- private registerMessage ( message : MessageResponse ) {
315+ private registerMessage ( message : MessageResponse < SCG > ) {
312316 if ( ! this . client . userID || message ?. user ?. id !== this . client . userID ) return ;
313317
314- const [ attachment ] = message . attachments ?? [ ] ;
315-
316- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
318+ if ( ! isValidLiveLocationMessage ( message ) ) {
317319 return ;
318320 }
319321
320322 this . state . next ( ( currentValue ) => ( { ...currentValue , targetMessages : [ ...currentValue . targetMessages , message ] } ) ) ;
321323 }
322324
323- private updateRegisteredMessage ( message : MessageResponse ) {
325+ private updateRegisteredMessage ( message : MessageResponse < SCG > ) {
324326 if ( ! this . client . userID || message ?. user ?. id !== this . client . userID ) return ;
325327
326328 const [ , targetMessageIndex ] = this . messagesById [ message . id ] ;
@@ -381,9 +383,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
381383
382384 if ( ! localMessage ) return ;
383385
384- const [ attachment ] = event . message . attachments ?? [ ] ;
385-
386- if ( ! isValidLiveLocationAttachment ( attachment ) ) {
386+ if ( ! isValidLiveLocationMessage ( event . message ) ) {
387387 this . unregisterMessage ( event . message ) ;
388388 } else {
389389 this . updateRegisteredMessage ( event . message ) ;
0 commit comments