1
1
/* refresh skip */
2
2
3
3
import { TagItem } from "@mutinywallet/mutiny-wasm" ;
4
- import {
5
- cache ,
6
- createAsync ,
7
- revalidate ,
8
- useNavigate ,
9
- useParams
10
- } from "@solidjs/router" ;
4
+ import { createAsync , useNavigate , useParams } from "@solidjs/router" ;
11
5
import {
12
6
createEffect ,
7
+ createMemo ,
13
8
createResource ,
14
9
createSignal ,
15
10
For ,
16
11
Match ,
17
12
onCleanup ,
13
+ onMount ,
18
14
Show ,
19
15
Suspense ,
20
16
Switch
@@ -40,7 +36,7 @@ import {
40
36
} from "~/components" ;
41
37
import { ParsedParams , toParsedParams } from "~/logic/waila" ;
42
38
import { useMegaStore } from "~/state/megaStore" ;
43
- import { timeAgo } from "~/utils" ;
39
+ import { createDeepSignal , timeAgo } from "~/utils" ;
44
40
45
41
type CombinedMessagesAndActivity =
46
42
| { kind : "message" ; content : FakeDirectMessage }
@@ -182,6 +178,72 @@ function SingleMessage(props: {
182
178
) ;
183
179
}
184
180
181
+ function MessageList ( props : {
182
+ convo : CombinedMessagesAndActivity [ ] ;
183
+ contact : TagItem ;
184
+ } ) {
185
+ let scrollRef : HTMLDivElement ;
186
+
187
+ onMount ( ( ) => {
188
+ scrollRef . scrollIntoView ( ) ;
189
+ } ) ;
190
+
191
+ // Details modal stuff
192
+ const [ detailsOpen , setDetailsOpen ] = createSignal ( false ) ;
193
+ const [ detailsKind , setDetailsKind ] = createSignal < HackActivityType > ( ) ;
194
+ const [ detailsId , setDetailsId ] = createSignal ( "" ) ;
195
+
196
+ function openDetailsModal ( id : string , kind : HackActivityType ) {
197
+ console . log ( "Opening details modal: " , id , kind ) ;
198
+
199
+ if ( ! id ) {
200
+ console . warn ( "No id provided to openDetailsModal" ) ;
201
+ return ;
202
+ }
203
+
204
+ setDetailsId ( id ) ;
205
+ setDetailsKind ( kind ) ;
206
+ setDetailsOpen ( true ) ;
207
+ }
208
+
209
+ return (
210
+ < >
211
+ < div class = "flex flex-col-reverse justify-end gap-4" >
212
+ < For each = { props . convo } >
213
+ { ( combined , index ) => (
214
+ < >
215
+ < Show when = { combined . kind === "activity" } >
216
+ < div class = "rounded-lg bg-m-grey-800 px-4 pt-4" >
217
+ < UnifiedActivityItem
218
+ item = { combined . content as IActivityItem }
219
+ onClick = { openDetailsModal }
220
+ />
221
+ </ div >
222
+ </ Show >
223
+ < Show when = { combined . kind === "message" } >
224
+ < SingleMessage
225
+ dm = { combined . content as FakeDirectMessage }
226
+ counterPartyNpub = { props . contact . npub || "" }
227
+ counterPartyContactId = { props . contact . id }
228
+ />
229
+ </ Show >
230
+ </ >
231
+ ) }
232
+ </ For >
233
+ </ div >
234
+ < div ref = { ( el ) => ( scrollRef = el ) } id = "scroll-to-me" />
235
+ < Show when = { detailsId ( ) && detailsKind ( ) } >
236
+ < ActivityDetailsModal
237
+ open = { detailsOpen ( ) }
238
+ kind = { detailsKind ( ) }
239
+ id = { detailsId ( ) }
240
+ setOpen = { setDetailsOpen }
241
+ />
242
+ </ Show >
243
+ </ >
244
+ ) ;
245
+ }
246
+
185
247
export function Chat ( ) {
186
248
const params = useParams ( ) ;
187
249
const [ state , actions ] = useMegaStore ( ) ;
@@ -193,24 +255,41 @@ export function Chat() {
193
255
return state . mutiny_wallet ?. get_tag_item ( params . id ) ;
194
256
} ) ;
195
257
258
+ const [ lastFetch , setLastFetch ] = createSignal ( 0n ) ;
259
+
196
260
const [ convo , { refetch } ] = createResource (
197
261
contact ,
198
- async ( contact : TagItem ) => {
262
+ async ( contact : TagItem , info ) => {
199
263
// if (!contact() || !contact()?.npub) return undefined;
200
264
if ( ! contact . npub ) return [ ] ;
201
265
try {
202
266
const activity = await state . mutiny_wallet ?. get_label_activity (
203
267
params . id
204
268
) ;
205
269
console . log ( "activity" , activity ) ;
270
+ const refetchingTimestamp = info . refetching as bigint ;
271
+ console . log ( "refetching since" , refetchingTimestamp ) ;
206
272
const convo = await state . mutiny_wallet ?. get_dm_conversation (
207
273
// Mutinynet npub, for testing
208
274
// "npub1qf8e8cvfp60ywrah984zgsn8veggcrsv2cvttdr47tgz05ypf5yszwx308",
209
275
contact . npub ,
210
276
20n ,
211
- undefined
277
+ refetchingTimestamp ? refetchingTimestamp : undefined
212
278
) ;
213
279
280
+ const lastConvo = info . value as CombinedMessagesAndActivity [ ] ;
281
+ if (
282
+ lastConvo &&
283
+ lastConvo . length === convo . length + activity . length
284
+ ) {
285
+ console . log ( "no new messages or activity" ) ;
286
+ return lastConvo ;
287
+ }
288
+
289
+ console . log ( "dms" , convo ) ;
290
+
291
+ setLastFetch ( BigInt ( Math . floor ( Date . now ( ) / 1000 ) ) ) ;
292
+
214
293
const dms = convo as FakeDirectMessage [ ] ;
215
294
const acts = activity as IActivityItem [ ] ;
216
295
@@ -248,14 +327,14 @@ export function Chat() {
248
327
return b_time - a_time ;
249
328
} ) ;
250
329
251
- return combined . reverse ( ) as CombinedMessagesAndActivity [ ] ;
252
-
253
- // return combined as FakeDirectMessage[];
254
- return [ ] ;
330
+ return combined as CombinedMessagesAndActivity [ ] ;
255
331
} catch ( e ) {
256
332
console . error ( "error getting convo:" , e ) ;
257
333
return [ ] ;
258
334
}
335
+ } ,
336
+ {
337
+ storage : createDeepSignal
259
338
}
260
339
) ;
261
340
@@ -270,33 +349,16 @@ export function Chat() {
270
349
) ;
271
350
console . log ( "dmResult:" , dmResult ) ;
272
351
setMessageValue ( "" ) ;
273
- refetch ( ) ;
274
- chatScrollRef ?. scrollTo ( {
275
- top : chatScrollRef . scrollHeight
276
- } ) ;
352
+ refetch ( lastFetch ( ) ) ;
277
353
} catch ( e ) {
278
354
console . error ( "error sending dm:" , e ) ;
279
355
}
280
356
setSending ( false ) ;
281
357
}
282
358
283
- let chatScrollRef : HTMLDivElement | null = null ;
284
-
285
- // For some reason I can't do scrolling here, but it works in send message
286
-
287
- // createEffect(() => {
288
- // if (convo.latest?.length && chatScrollRef) {
289
- // console.log("scrolling");
290
-
291
- // chatScrollRef?.scrollTo({
292
- // top: chatScrollRef.scrollHeight
293
- // });
294
- // }
295
- // });
296
-
297
359
createEffect ( ( ) => {
298
360
const interval = setInterval ( ( ) => {
299
- refetch ( ) ;
361
+ refetch ( lastFetch ( ) ) ;
300
362
} , 5000 ) ; // Poll every 5 seconds
301
363
onCleanup ( ( ) => {
302
364
clearInterval ( interval ) ;
@@ -344,24 +406,6 @@ export function Chat() {
344
406
} ) ;
345
407
}
346
408
347
- // Details modal stuff
348
- const [ detailsOpen , setDetailsOpen ] = createSignal ( false ) ;
349
- const [ detailsKind , setDetailsKind ] = createSignal < HackActivityType > ( ) ;
350
- const [ detailsId , setDetailsId ] = createSignal ( "" ) ;
351
-
352
- function openDetailsModal ( id : string , kind : HackActivityType ) {
353
- console . log ( "Opening details modal: " , id , kind ) ;
354
-
355
- if ( ! id ) {
356
- console . warn ( "No id provided to openDetailsModal" ) ;
357
- return ;
358
- }
359
-
360
- setDetailsId ( id ) ;
361
- setDetailsKind ( kind ) ;
362
- setDetailsOpen ( true ) ;
363
- }
364
-
365
409
return (
366
410
< Transition
367
411
mode = "outin"
@@ -393,10 +437,7 @@ export function Chat() {
393
437
>
394
438
< MutinyWalletGuard >
395
439
< main class = "mx-auto grid h-[100dvh] w-full max-w-[600px] grid-cols-1 grid-rows-[minmax(10px,1fr)_4rem] flex-col overflow-y-hidden safe-top safe-bottom" >
396
- < div
397
- class = "overflow-y-auto"
398
- ref = { ( el ) => ( chatScrollRef = el ) }
399
- >
440
+ < div class = "overflow-y-auto" >
400
441
< div class = "fixed top-0 z-50 flex w-full flex-col gap-2 bg-m-grey-975/70 p-4 backdrop-blur-lg" >
401
442
{ /* <BackLink href="/" /> */ }
402
443
< BackPop default = "/search" />
@@ -411,51 +452,16 @@ export function Chat() {
411
452
{ /* <pre class="whitespace-pre-wrap break-all">
412
453
{JSON.stringify(convo(), null, 2)}
413
454
</pre> */ }
414
- < div class = "flex flex-col gap-4 p-4" >
455
+ < div class = "p-4" >
415
456
< Suspense >
416
457
< Show when = { contact ( ) } >
417
458
< Suspense fallback = { < LoadingShimmer /> } >
418
- < For each = { convo . latest } >
419
- { ( combined ) => (
420
- < >
421
- < Show
422
- when = {
423
- combined . kind ===
424
- "activity"
425
- }
426
- >
427
- < div class = "rounded-lg bg-m-grey-800 px-4 pt-4" >
428
- < UnifiedActivityItem
429
- item = {
430
- combined . content as IActivityItem
431
- }
432
- onClick = {
433
- openDetailsModal
434
- }
435
- />
436
- </ div >
437
- </ Show >
438
- < Show
439
- when = {
440
- combined . kind ===
441
- "message"
442
- }
443
- >
444
- < SingleMessage
445
- dm = {
446
- combined . content as FakeDirectMessage
447
- }
448
- counterPartyNpub = {
449
- contact ( ) ! . npub !
450
- }
451
- counterPartyContactId = {
452
- params . id
453
- }
454
- />
455
- </ Show >
456
- </ >
457
- ) }
458
- </ For >
459
+ < Show when = { convo . latest } >
460
+ < MessageList
461
+ convo = { convo . latest }
462
+ contact = { contact ( ) ! }
463
+ />
464
+ </ Show >
459
465
</ Suspense >
460
466
</ Show >
461
467
</ Suspense >
@@ -511,14 +517,6 @@ export function Chat() {
511
517
</ div >
512
518
</ div >
513
519
</ main >
514
- < Show when = { detailsId ( ) && detailsKind ( ) } >
515
- < ActivityDetailsModal
516
- open = { detailsOpen ( ) }
517
- kind = { detailsKind ( ) }
518
- id = { detailsId ( ) }
519
- setOpen = { setDetailsOpen }
520
- />
521
- </ Show >
522
520
</ MutinyWalletGuard >
523
521
</ Transition >
524
522
) ;
0 commit comments