mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(api): respect age gating in search and stabilise discovery (#2598)
This commit is contained in:
1 parent
20a15ac11d
commit
55846b24ea
10 files changed
+250
-49
No files matched your search
@@ -99,9 +99,10 @@ export const DiscoveryPage = observer(function DiscoveryPage() {
|
||||
return Math.min(SKELETON_DISCOVERY_MAX_COLUMNS, Math.max(1, columnsThatFit));
|
||||
}, [containerWidth, zoomLevel]);
|
||||
const guilds = Discovery.guilds;
|
||||
const loadedCount = Discovery.loadedCount;
|
||||
const searchActive = Discovery.query.length > 0;
|
||||
const rowCount = columns > 0 ? Math.ceil(guilds.length / columns) : 0;
|
||||
const hasMore = guilds.length < Discovery.total;
|
||||
const hasMore = loadedCount < Discovery.total;
|
||||
const virtualizer = useVirtualizer({
|
||||
count: rowCount,
|
||||
getScrollElement: () => scrollerRef.current?.getViewportElement() ?? null,
|
||||
@@ -114,10 +115,10 @@ export const DiscoveryPage = observer(function DiscoveryPage() {
|
||||
return;
|
||||
}
|
||||
void Discovery.search({
|
||||
offset: guilds.length,
|
||||
offset: loadedCount,
|
||||
limit: PAGE_SIZE,
|
||||
});
|
||||
}, [guilds.length, hasMore]);
|
||||
}, [loadedCount, hasMore]);
|
||||
useEffect(() => {
|
||||
const items = virtualizer.getVirtualItems();
|
||||
const lastItem = items[items.length - 1];
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {DiscoveryGuild, DiscoverySearchResponse} from '@app/features/discovery/commands/DiscoveryCommands';
|
||||
import * as DiscoveryCommands from '@app/features/discovery/commands/DiscoveryCommands';
|
||||
import {beforeEach, describe, expect, test, vi} from 'vitest';
|
||||
|
||||
import Discovery from './Discovery';
|
||||
|
||||
vi.mock('@app/features/discovery/commands/DiscoveryCommands', () => ({
|
||||
searchGuilds: vi.fn(),
|
||||
getCategories: vi.fn(),
|
||||
}));
|
||||
|
||||
function guild(id: string, memberCount: number): DiscoveryGuild {
|
||||
return {
|
||||
id,
|
||||
name: `Guild ${id}`,
|
||||
icon: null,
|
||||
banner: null,
|
||||
description: null,
|
||||
category_type: 0,
|
||||
primary_language: null,
|
||||
custom_tags: [],
|
||||
member_count: memberCount,
|
||||
online_count: 0,
|
||||
features: [],
|
||||
verification_level: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function page(guilds: Array<DiscoveryGuild>, total: number): DiscoverySearchResponse {
|
||||
return {guilds, total, categoryCounts: null};
|
||||
}
|
||||
|
||||
describe('Discovery.search', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(DiscoveryCommands.searchGuilds).mockReset();
|
||||
Discovery.reset();
|
||||
});
|
||||
|
||||
test('does not append a guild that a previous page already returned', async () => {
|
||||
vi.mocked(DiscoveryCommands.searchGuilds)
|
||||
.mockResolvedValueOnce(page([guild('1', 50), guild('2', 40)], 4))
|
||||
.mockResolvedValueOnce(page([guild('2', 40), guild('3', 30)], 4));
|
||||
await Discovery.search({limit: 2, offset: 0});
|
||||
await Discovery.search({limit: 2, offset: Discovery.loadedCount});
|
||||
expect(Discovery.guilds.map((entry) => entry.id)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
|
||||
test('advances the pagination offset by what the server returned, not by what survived deduping', async () => {
|
||||
vi.mocked(DiscoveryCommands.searchGuilds)
|
||||
.mockResolvedValueOnce(page([guild('1', 50), guild('2', 40)], 4))
|
||||
.mockResolvedValueOnce(page([guild('2', 40), guild('3', 30)], 4));
|
||||
await Discovery.search({limit: 2, offset: 0});
|
||||
await Discovery.search({limit: 2, offset: Discovery.loadedCount});
|
||||
expect(Discovery.loadedCount).toBe(4);
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,7 @@ const DEFAULT_DISCOVERY_PAGE_SIZE = 36;
|
||||
|
||||
class Discovery {
|
||||
guilds: Array<DiscoveryGuild> = [];
|
||||
loadedCount = 0;
|
||||
total = 0;
|
||||
loading = false;
|
||||
error = false;
|
||||
@@ -53,6 +54,7 @@ class Discovery {
|
||||
this.error = false;
|
||||
if (offset === 0 && searchModeChanged) {
|
||||
this.guilds = [];
|
||||
this.loadedCount = 0;
|
||||
this.total = 0;
|
||||
}
|
||||
this.query = query;
|
||||
@@ -78,8 +80,10 @@ class Discovery {
|
||||
if (offset === 0) {
|
||||
this.guilds = result.guilds;
|
||||
} else {
|
||||
this.guilds = [...this.guilds, ...result.guilds];
|
||||
const seen = new Set(this.guilds.map((guild) => guild.id));
|
||||
this.guilds = [...this.guilds, ...result.guilds.filter((guild) => !seen.has(guild.id))];
|
||||
}
|
||||
this.loadedCount = offset + result.guilds.length;
|
||||
this.total = result.total;
|
||||
this.categoryCounts = result.categoryCounts;
|
||||
this.loading = false;
|
||||
@@ -136,6 +140,7 @@ class Discovery {
|
||||
reset(): void {
|
||||
this.activeSearchToken += 1;
|
||||
this.guilds = [];
|
||||
this.loadedCount = 0;
|
||||
this.total = 0;
|
||||
this.categoryCounts = null;
|
||||
this.loading = false;
|
||||
|
||||
Reference in new issue
Block a user