+5
-1
src/modules/cards/infrastructure/repositories/query-services/UrlCardQueryService.ts
+5
-1
src/modules/cards/infrastructure/repositories/query-services/UrlCardQueryService.ts
···
359
359
options: CardQueryOptions,
360
360
): Promise<PaginatedQueryResult<LibraryForUrlDTO>> {
361
361
try {
362
-
const { page, limit } = options;
362
+
const { page, limit, sortBy, sortOrder } = options;
363
363
const offset = (page - 1) * limit;
364
+
365
+
// Build the sort order
366
+
const orderDirection = sortOrder === SortOrder.ASC ? asc : desc;
364
367
365
368
// Get all URL cards with this URL and their library memberships
366
369
const librariesQuery = this.db
···
376
379
.from(libraryMemberships)
377
380
.innerJoin(cards, eq(libraryMemberships.cardId, cards.id))
378
381
.where(and(eq(cards.url, url), eq(cards.type, CardTypeEnum.URL)))
382
+
.orderBy(orderDirection(this.getSortColumn(sortBy)))
379
383
.limit(limit)
380
384
.offset(offset);
381
385
+1
-1
src/modules/cards/tests/application/GetLibrariesForUrlUseCase.test.ts
+1
-1
src/modules/cards/tests/application/GetLibrariesForUrlUseCase.test.ts
···
319
319
expect(result.isOk()).toBe(true);
320
320
const response = result.unwrap();
321
321
322
-
expect(response.sorting.sortBy).toBe(CardSortField.UPDATED_AT);
322
+
expect(response.sorting.sortBy).toBe(CardSortField.CREATED_AT);
323
323
expect(response.sorting.sortOrder).toBe(SortOrder.DESC);
324
324
});
325
325
+276
src/modules/cards/tests/infrastructure/DrizzleCardQueryRepository.getLibrariesForUrl.integration.test.ts
+276
src/modules/cards/tests/infrastructure/DrizzleCardQueryRepository.getLibrariesForUrl.integration.test.ts
···
15
15
import { CardSortField, SortOrder } from '../../domain/ICardQueryRepository';
16
16
import { createTestSchema } from '../test-utils/createTestSchema';
17
17
import { CardTypeEnum } from '../../domain/value-objects/CardType';
18
+
import { PublishedRecordId } from '../../domain/value-objects/PublishedRecordId';
18
19
19
20
describe('DrizzleCardQueryRepository - getLibrariesForUrl', () => {
20
21
let container: StartedPostgreSqlContainer;
···
281
282
// Should return empty since card is not in any library
282
283
expect(result.items).toHaveLength(0);
283
284
expect(result.totalCount).toBe(0);
285
+
});
286
+
});
287
+
288
+
describe('sorting', () => {
289
+
it('should sort by createdAt in descending order by default', async () => {
290
+
const testUrl = 'https://example.com/sort-test';
291
+
const url = URL.create(testUrl).unwrap();
292
+
293
+
// Create cards with different creation times
294
+
const card1 = new CardBuilder()
295
+
.withCuratorId(curator1.value)
296
+
.withType(CardTypeEnum.URL)
297
+
.withUrl(url)
298
+
.buildOrThrow();
299
+
300
+
await new Promise((resolve) => setTimeout(resolve, 1000));
301
+
const card2 = new CardBuilder()
302
+
.withCuratorId(curator2.value)
303
+
.withType(CardTypeEnum.URL)
304
+
.withUrl(url)
305
+
.buildOrThrow();
306
+
307
+
await new Promise((resolve) => setTimeout(resolve, 1000));
308
+
const card3 = new CardBuilder()
309
+
.withCuratorId(curator3.value)
310
+
.withType(CardTypeEnum.URL)
311
+
.withUrl(url)
312
+
.buildOrThrow();
313
+
314
+
card1.addToLibrary(curator1);
315
+
card2.addToLibrary(curator2);
316
+
card3.addToLibrary(curator3);
317
+
318
+
// Save cards with slight delays to ensure different timestamps
319
+
await cardRepository.save(card1);
320
+
await new Promise((resolve) => setTimeout(resolve, 10));
321
+
await cardRepository.save(card2);
322
+
await new Promise((resolve) => setTimeout(resolve, 10));
323
+
await cardRepository.save(card3);
324
+
325
+
const result = await queryRepository.getLibrariesForUrl(testUrl, {
326
+
page: 1,
327
+
limit: 10,
328
+
sortBy: CardSortField.CREATED_AT,
329
+
sortOrder: SortOrder.DESC,
330
+
});
331
+
332
+
expect(result.items).toHaveLength(3);
333
+
334
+
// Should be sorted by creation time, newest first
335
+
const cardIds = result.items.map((lib) => lib.card.id);
336
+
expect(cardIds[0]).toBe(card3.cardId.getStringValue()); // Most recent
337
+
expect(cardIds[1]).toBe(card2.cardId.getStringValue()); // Middle
338
+
expect(cardIds[2]).toBe(card1.cardId.getStringValue()); // Oldest
339
+
});
340
+
341
+
it('should sort by createdAt in ascending order when specified', async () => {
342
+
const testUrl = 'https://example.com/sort-asc-test';
343
+
const url = URL.create(testUrl).unwrap();
344
+
345
+
// Create cards with different creation times
346
+
const card1 = new CardBuilder()
347
+
.withCuratorId(curator1.value)
348
+
.withType(CardTypeEnum.URL)
349
+
.withUrl(url)
350
+
.buildOrThrow();
351
+
352
+
const card2 = new CardBuilder()
353
+
.withCuratorId(curator2.value)
354
+
.withType(CardTypeEnum.URL)
355
+
.withUrl(url)
356
+
.buildOrThrow();
357
+
358
+
card1.addToLibrary(curator1);
359
+
card2.addToLibrary(curator2);
360
+
361
+
// Save cards with slight delay to ensure different timestamps
362
+
await cardRepository.save(card1);
363
+
await new Promise((resolve) => setTimeout(resolve, 10));
364
+
await cardRepository.save(card2);
365
+
366
+
const result = await queryRepository.getLibrariesForUrl(testUrl, {
367
+
page: 1,
368
+
limit: 10,
369
+
sortBy: CardSortField.CREATED_AT,
370
+
sortOrder: SortOrder.ASC,
371
+
});
372
+
373
+
expect(result.items).toHaveLength(2);
374
+
375
+
// Should be sorted by creation time, oldest first
376
+
const cardIds = result.items.map((lib) => lib.card.id);
377
+
expect(cardIds[0]).toBe(card1.cardId.getStringValue()); // Oldest
378
+
expect(cardIds[1]).toBe(card2.cardId.getStringValue()); // Newest
379
+
});
380
+
381
+
it('should sort by updatedAt in descending order', async () => {
382
+
const testUrl = 'https://example.com/sort-updated-test';
383
+
const url = URL.create(testUrl).unwrap();
384
+
385
+
// Create cards
386
+
const card1 = new CardBuilder()
387
+
.withCuratorId(curator1.value)
388
+
.withType(CardTypeEnum.URL)
389
+
.withUrl(url)
390
+
.buildOrThrow();
391
+
392
+
const card2 = new CardBuilder()
393
+
.withCuratorId(curator2.value)
394
+
.withType(CardTypeEnum.URL)
395
+
.withUrl(url)
396
+
.buildOrThrow();
397
+
398
+
card1.addToLibrary(curator1);
399
+
card2.addToLibrary(curator2);
400
+
401
+
// Save cards
402
+
await cardRepository.save(card1);
403
+
await cardRepository.save(card2);
404
+
405
+
// Update card1 to have a more recent updatedAt
406
+
await new Promise((resolve) => setTimeout(resolve, 1000));
407
+
card1.markAsPublished(
408
+
PublishedRecordId.create({
409
+
uri: 'at://did:plc:publishedrecord1',
410
+
cid: 'bafyreicpublishedrecord1',
411
+
}),
412
+
);
413
+
await cardRepository.save(card1); // This should update the updatedAt timestamp
414
+
415
+
const result = await queryRepository.getLibrariesForUrl(testUrl, {
416
+
page: 1,
417
+
limit: 10,
418
+
sortBy: CardSortField.UPDATED_AT,
419
+
sortOrder: SortOrder.DESC,
420
+
});
421
+
422
+
expect(result.items).toHaveLength(2);
423
+
424
+
// card1 should be first since it was updated more recently
425
+
const cardIds = result.items.map((lib) => lib.card.id);
426
+
expect(cardIds[0]).toBe(card1.cardId.getStringValue()); // Most recently updated
427
+
expect(cardIds[1]).toBe(card2.cardId.getStringValue()); // Less recently updated
428
+
});
429
+
430
+
it('should sort by libraryCount in descending order', async () => {
431
+
const testUrl = 'https://example.com/sort-library-count-test';
432
+
const url = URL.create(testUrl).unwrap();
433
+
434
+
// Create cards
435
+
const card1 = new CardBuilder()
436
+
.withCuratorId(curator1.value)
437
+
.withType(CardTypeEnum.URL)
438
+
.withUrl(url)
439
+
.buildOrThrow();
440
+
441
+
const card2 = new CardBuilder()
442
+
.withCuratorId(curator2.value)
443
+
.withType(CardTypeEnum.URL)
444
+
.withUrl(url)
445
+
.buildOrThrow();
446
+
447
+
const card3 = new CardBuilder()
448
+
.withCuratorId(curator3.value)
449
+
.withType(CardTypeEnum.URL)
450
+
.withUrl(url)
451
+
.buildOrThrow();
452
+
453
+
// Add cards to libraries with different counts
454
+
card1.addToLibrary(curator1);
455
+
456
+
card2.addToLibrary(curator2);
457
+
card2.addToLibrary(curator1); // card2 has 2 library memberships
458
+
459
+
card3.addToLibrary(curator3);
460
+
card3.addToLibrary(curator1); // card3 has 3 library memberships
461
+
card3.addToLibrary(curator2);
462
+
463
+
await cardRepository.save(card1);
464
+
await cardRepository.save(card2);
465
+
await cardRepository.save(card3);
466
+
467
+
const result = await queryRepository.getLibrariesForUrl(testUrl, {
468
+
page: 1,
469
+
limit: 10,
470
+
sortBy: CardSortField.LIBRARY_COUNT,
471
+
sortOrder: SortOrder.DESC,
472
+
});
473
+
474
+
// Should return all library memberships, but sorted by the card's library count
475
+
expect(result.items.length).toBeGreaterThan(0);
476
+
477
+
// Group by card ID to check sorting
478
+
const cardGroups = new Map<string, any[]>();
479
+
result.items.forEach((item) => {
480
+
const cardId = item.card.id;
481
+
if (!cardGroups.has(cardId)) {
482
+
cardGroups.set(cardId, []);
483
+
}
484
+
cardGroups.get(cardId)!.push(item);
485
+
});
486
+
487
+
// Get the first occurrence of each card to check library count ordering
488
+
const uniqueCards = Array.from(cardGroups.entries()).map(
489
+
([cardId, items]) => ({
490
+
cardId,
491
+
libraryCount: items[0]!.card.libraryCount,
492
+
}),
493
+
);
494
+
495
+
// Should be sorted by library count descending
496
+
for (let i = 0; i < uniqueCards.length - 1; i++) {
497
+
expect(uniqueCards[i]!.libraryCount).toBeGreaterThanOrEqual(
498
+
uniqueCards[i + 1]!.libraryCount,
499
+
);
500
+
}
501
+
});
502
+
503
+
it('should sort by libraryCount in ascending order when specified', async () => {
504
+
const testUrl = 'https://example.com/sort-library-count-asc-test';
505
+
const url = URL.create(testUrl).unwrap();
506
+
507
+
// Create cards with different library counts
508
+
const card1 = new CardBuilder()
509
+
.withCuratorId(curator1.value)
510
+
.withType(CardTypeEnum.URL)
511
+
.withUrl(url)
512
+
.buildOrThrow();
513
+
514
+
const card2 = new CardBuilder()
515
+
.withCuratorId(curator2.value)
516
+
.withType(CardTypeEnum.URL)
517
+
.withUrl(url)
518
+
.buildOrThrow();
519
+
520
+
// card1 has 1 library membership, card2 has 2
521
+
card1.addToLibrary(curator1);
522
+
card2.addToLibrary(curator2);
523
+
card2.addToLibrary(curator1);
524
+
525
+
await cardRepository.save(card1);
526
+
await cardRepository.save(card2);
527
+
528
+
const result = await queryRepository.getLibrariesForUrl(testUrl, {
529
+
page: 1,
530
+
limit: 10,
531
+
sortBy: CardSortField.LIBRARY_COUNT,
532
+
sortOrder: SortOrder.ASC,
533
+
});
534
+
535
+
expect(result.items.length).toBeGreaterThan(0);
536
+
537
+
// Group by card ID and check ascending order
538
+
const cardGroups = new Map<string, any[]>();
539
+
result.items.forEach((item) => {
540
+
const cardId = item.card.id;
541
+
if (!cardGroups.has(cardId)) {
542
+
cardGroups.set(cardId, []);
543
+
}
544
+
cardGroups.get(cardId)!.push(item);
545
+
});
546
+
547
+
const uniqueCards = Array.from(cardGroups.entries()).map(
548
+
([cardId, items]) => ({
549
+
cardId,
550
+
libraryCount: items[0]!.card.libraryCount,
551
+
}),
552
+
);
553
+
554
+
// Should be sorted by library count ascending
555
+
for (let i = 0; i < uniqueCards.length - 1; i++) {
556
+
expect(uniqueCards[i]!.libraryCount).toBeLessThanOrEqual(
557
+
uniqueCards[i + 1]!.libraryCount,
558
+
);
559
+
}
284
560
});
285
561
});
286
562
+1
-1
src/webapp/app/(dashboard)/error.tsx
+1
-1
src/webapp/app/(dashboard)/error.tsx
+15
src/webapp/app/bookmarklet/layout.tsx
+15
src/webapp/app/bookmarklet/layout.tsx
···
1
+
import type { Metadata } from 'next';
2
+
3
+
export const metadata: Metadata = {
4
+
title: 'Semble bookmarklet',
5
+
description:
6
+
'Learn how to add our bookmarklet to your browser to quickly open any webpage in Semble.',
7
+
};
8
+
9
+
interface Props {
10
+
children: React.ReactNode;
11
+
}
12
+
13
+
export default function Layout(props: Props) {
14
+
return props.children;
15
+
}
+83
-65
src/webapp/app/bookmarklet/page.tsx
+83
-65
src/webapp/app/bookmarklet/page.tsx
···
9
9
Code,
10
10
Alert,
11
11
Box,
12
+
Badge,
13
+
Image,
12
14
Group,
15
+
Anchor,
16
+
CopyButton,
13
17
} from '@mantine/core';
14
-
import { useState } from 'react';
15
-
import { BiInfoCircle } from 'react-icons/bi';
18
+
import SembleLogo from '@/assets/semble-logo.svg';
19
+
import Link from 'next/link';
16
20
17
21
export default function BookmarkletPage() {
18
-
const [copied, setCopied] = useState(false);
22
+
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://127.0.0.1:4000';
19
23
20
-
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
21
-
22
24
const bookmarkletCode = `javascript:(function(){
23
25
const currentUrl = window.location.href;
24
26
const sembleUrl = '${appUrl}/url?id=' + currentUrl;
25
27
window.open(sembleUrl, '_blank');
26
-
})();`;
27
-
28
-
const handleCopy = async () => {
29
-
try {
30
-
await navigator.clipboard.writeText(bookmarkletCode);
31
-
setCopied(true);
32
-
setTimeout(() => setCopied(false), 2000);
33
-
} catch (err) {
34
-
console.error('Failed to copy bookmarklet:', err);
35
-
}
36
-
};
28
+
})();`;
37
29
38
30
// Create the bookmarklet link using dangerouslySetInnerHTML to bypass React's security check
39
31
const createBookmarkletLink = () => {
40
32
return {
41
-
__html: `<a href="${bookmarkletCode}" style="text-decoration: none; padding: 8px 16px; background-color: var(--mantine-color-blue-6); color: white; border-radius: 4px; display: inline-flex; align-items: center; gap: 8px;"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>Open in Semble</a>`
33
+
__html: `<a href="${bookmarkletCode}" style="text-decoration: none; padding: 8px 16px; background-color: var(--mantine-color-tangerine-6); color: white; border-radius: 100px; display: inline-flex; align-items: center; gap: 8px; font-weight: 600;"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>Open in Semble</a>`,
42
34
};
43
35
};
44
36
45
37
return (
46
-
<Container size="md" py="xl">
38
+
<Container size="sm" p="md">
47
39
<Stack gap="xl">
48
-
<Stack gap="md">
49
-
<Title order={1}>Semble Bookmarklet</Title>
50
-
<Text size="lg" c="dimmed">
51
-
Add this bookmarklet to your browser to quickly open any webpage in Semble
52
-
and see what your network has shared about it.
53
-
</Text>
40
+
<Stack gap="xs" align="center">
41
+
<Stack align="center" gap={'xs'}>
42
+
<Anchor component={Link} href={'/'}>
43
+
<Image
44
+
src={SembleLogo.src}
45
+
alt="Semble logo"
46
+
w={48}
47
+
h={64.5}
48
+
mx={'auto'}
49
+
/>
50
+
<Badge size="sm">Alpha</Badge>
51
+
</Anchor>
52
+
</Stack>
53
+
<Stack gap={'xs'} align="center">
54
+
<Title order={1}>Semble Bookmarklet</Title>
55
+
<Title
56
+
order={2}
57
+
size="xl"
58
+
c="dimmed"
59
+
fw={600}
60
+
maw={500}
61
+
ta={'center'}
62
+
>
63
+
Add this bookmarklet to your browser to quickly open any webpage
64
+
in Semble.
65
+
</Title>
66
+
</Stack>
54
67
</Stack>
55
68
56
-
<Alert icon={<BiInfoCircle />} title="How to install" color="blue">
69
+
<Alert title="How to install" color="grape">
57
70
<Stack gap="sm">
58
-
<Text>
59
-
1. Copy the bookmarklet code below or drag the button to your bookmarks bar
60
-
</Text>
61
-
<Text>
62
-
2. When you're on any webpage, click the bookmarklet to open it in Semble
63
-
</Text>
64
-
<Text>
65
-
3. You'll see who in your network has shared that URL and any notes they've added
66
-
</Text>
71
+
<Group gap={'xs'}>
72
+
<Badge size="md" color="grape" circle>
73
+
1
74
+
</Badge>
75
+
<Text fw={500} c="grape">
76
+
Copy the bookmarklet code below or drag the button to your
77
+
bookmarks bar
78
+
</Text>
79
+
</Group>
80
+
<Group gap={'xs'}>
81
+
<Badge size="md" color="grape" circle>
82
+
2
83
+
</Badge>
84
+
85
+
<Text fw={500} c={'grape'}>
86
+
{
87
+
"When you're on any webpage, click the bookmarklet to open it in Semble"
88
+
}
89
+
</Text>
90
+
</Group>
67
91
</Stack>
68
92
</Alert>
69
93
70
94
<Stack gap="md">
71
-
<Title order={2} size="h3">
72
-
Method 1: Drag to Bookmarks Bar
73
-
</Title>
74
-
<Text c="dimmed">
75
-
Drag this button directly to your browser's bookmarks bar:
76
-
</Text>
95
+
<Stack gap={'xs'}>
96
+
<Title order={3}>Method 1: Drag to Bookmarks Bar</Title>
97
+
<Text c="dimmed" fw={500}>
98
+
{"Drag this button directly to your browser's bookmarks bar:"}
99
+
</Text>
100
+
</Stack>
77
101
<Group>
78
102
<Box dangerouslySetInnerHTML={createBookmarkletLink()} />
79
103
</Group>
80
104
</Stack>
81
105
82
106
<Stack gap="md">
83
-
<Title order={2} size="h3">
84
-
Method 2: Copy Code
85
-
</Title>
86
-
<Text c="dimmed">
87
-
Copy this code and create a new bookmark with it as the URL:
88
-
</Text>
107
+
<Stack gap={'xs'}>
108
+
<Title order={3}>Method 2: Copy Code</Title>
109
+
<Text c="dimmed" fw={500}>
110
+
Copy this code and create a new bookmark with it as the URL:
111
+
</Text>
112
+
</Stack>
89
113
<Box pos="relative">
90
114
<Code
91
115
block
···
98
122
>
99
123
{bookmarkletCode}
100
124
</Code>
101
-
<Button
102
-
size="xs"
103
-
variant="light"
104
-
onClick={handleCopy}
105
-
style={{
106
-
position: 'absolute',
107
-
top: '8px',
108
-
right: '8px',
109
-
}}
110
-
>
111
-
{copied ? 'Copied!' : 'Copy'}
112
-
</Button>
125
+
<CopyButton value={bookmarkletCode}>
126
+
{({ copied, copy }) => (
127
+
<Button
128
+
color="dark"
129
+
pos={'absolute'}
130
+
top={12}
131
+
right={12}
132
+
onClick={copy}
133
+
>
134
+
{copied ? 'Copied!' : 'Copy'}
135
+
</Button>
136
+
)}
137
+
</CopyButton>
113
138
</Box>
114
139
</Stack>
115
-
116
-
<Alert icon={<BiInfoCircle />} title="Note" color="gray">
117
-
<Text>
118
-
This bookmarklet will open Semble in a new tab. Make sure you're logged in
119
-
to see personalized results from your network.
120
-
</Text>
121
-
</Alert>
122
140
</Stack>
123
141
</Container>
124
142
);
+1
-1
src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx
+1
-1
src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx
+1
-1
src/webapp/features/cards/lib/cardKeys.ts
+1
-1
src/webapp/features/cards/lib/cardKeys.ts
···
2
2
all: () => ['cards'] as const,
3
3
card: (id: string) => [...cardKeys.all(), id] as const,
4
4
byUrl: (url: string) => [...cardKeys.all(), url] as const,
5
-
mine: () => [...cardKeys.all(), 'mine'] as const,
5
+
mine: (limit?: number) => [...cardKeys.all(), 'mine', limit] as const,
6
6
search: (query: string) => [...cardKeys.all(), 'search', query],
7
7
bySembleUrl: (url: string) => [...cardKeys.all(), url],
8
8
libraries: (id: string) => [...cardKeys.all(), 'libraries', id],
+1
-1
src/webapp/features/cards/lib/queries/useMyCards.tsx
+1
-1
src/webapp/features/cards/lib/queries/useMyCards.tsx
+1
-1
src/webapp/features/collections/components/collectionCard/CollectionCard.tsx
+1
-1
src/webapp/features/collections/components/collectionCard/CollectionCard.tsx
+1
-1
src/webapp/features/collections/lib/collectionKeys.ts
+1
-1
src/webapp/features/collections/lib/collectionKeys.ts
···
1
1
export const collectionKeys = {
2
2
all: () => ['collections'] as const,
3
3
collection: (id: string) => [...collectionKeys.all(), id] as const,
4
-
mine: () => [...collectionKeys.all(), 'mine'] as const,
4
+
mine: (limit?: number) => [...collectionKeys.all(), 'mine', limit] as const,
5
5
search: (query: string) => [...collectionKeys.all(), 'search', query],
6
6
bySembleUrl: (url: string) => [...collectionKeys.all(), url],
7
7
infinite: (id?: string, limit?: number) => [
+1
-1
src/webapp/features/collections/lib/mutations/useCreateCollection.tsx
+1
-1
src/webapp/features/collections/lib/mutations/useCreateCollection.tsx
···
14
14
// Do UI related things like redirects or showing toast notifications in mutate callbacks. If the user navigated away from the current screen before the mutation finished, those will purposefully not fire
15
15
// https://tkdodo.eu/blog/mastering-mutations-in-react-query#some-callbacks-might-not-fire
16
16
onSuccess: () => {
17
-
queryClient.invalidateQueries({ queryKey: collectionKeys.infinite() });
17
+
queryClient.invalidateQueries({ queryKey: collectionKeys.all() });
18
18
queryClient.refetchQueries({ queryKey: collectionKeys.mine() });
19
19
},
20
20
});
+1
-1
src/webapp/features/collections/lib/queries/useMyCollections.tsx
+1
-1
src/webapp/features/collections/lib/queries/useMyCollections.tsx
···
10
10
const limit = props?.limit ?? 15;
11
11
12
12
return useSuspenseInfiniteQuery({
13
-
queryKey: collectionKeys.mine(),
13
+
queryKey: collectionKeys.mine(props?.limit),
14
14
initialPageParam: 1,
15
15
queryFn: ({ pageParam }) => getMyCollections({ limit, page: pageParam }),
16
16
getNextPageParam: (lastPage) => {
+1
-1
src/webapp/features/home/containers/homeContainer/HomeContainer.tsx
+1
-1
src/webapp/features/home/containers/homeContainer/HomeContainer.tsx
···
26
26
import { useNavbarContext } from '@/providers/navbar';
27
27
28
28
export default function HomeContainer() {
29
-
const { data: collectionsData } = useMyCollections({ limit: 8 });
29
+
const { data: collectionsData } = useMyCollections({ limit: 4 });
30
30
const { data: myCardsData } = useMyCards({ limit: 8 });
31
31
const { data: profile } = useMyProfile();
32
32
+1
-1
src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx
+1
-1
src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx
+1
src/webapp/features/notes/components/noteCard/NoteCard.tsx
+1
src/webapp/features/notes/components/noteCard/NoteCard.tsx
+1
-1
src/webapp/features/notes/components/noteCardModal/NoteCardModalContent.tsx
+1
-1
src/webapp/features/notes/components/noteCardModal/NoteCardModalContent.tsx
+1
-1
src/webapp/features/profile/components/profileHoverCard/ProfileHoverCard.tsx
+1
-1
src/webapp/features/profile/components/profileHoverCard/ProfileHoverCard.tsx
+5
-1
src/webapp/features/semble/containers/sembleAside/SembleAside.tsx
+5
-1
src/webapp/features/semble/containers/sembleAside/SembleAside.tsx