From 95ea2a5f2373920655c91a89a76b03cacf72fc42 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 11 Jun 2025 23:12:03 +0200 Subject: [PATCH] fix loading feed --- src/app/api/client.ts | 8 +-- src/app/feed/pages/HomePage.tsx | 88 ++++++++++++++---------------- src/app/feed/posts/postsService.ts | 26 +++------ src/utils/delay.ts | 3 + 4 files changed, 54 insertions(+), 71 deletions(-) create mode 100644 src/utils/delay.ts diff --git a/src/app/api/client.ts b/src/app/api/client.ts index 19b8899..63cce0c 100644 --- a/src/app/api/client.ts +++ b/src/app/api/client.ts @@ -1,10 +1,8 @@ import { paths } from './schema.ts' -import createClient, { Client, Middleware } from 'openapi-fetch' +import createClient, { Middleware } from 'openapi-fetch' import { dispatchMessage } from '../messageBus/messageBus.ts' -export type ApiClient = Client - -export function initClient(): ApiClient { +export const initClient = () => { const client = createClient({ baseUrl: import.meta.env.VITE_API_URL }) const UnauthorizedHandlerMiddleware: Middleware = { async onResponse({ response }) { @@ -17,3 +15,5 @@ export function initClient(): ApiClient { client.use(UnauthorizedHandlerMiddleware) return client } + +export type ApiClient = ReturnType diff --git a/src/app/feed/pages/HomePage.tsx b/src/app/feed/pages/HomePage.tsx index 738d168..c470d39 100644 --- a/src/app/feed/pages/HomePage.tsx +++ b/src/app/feed/pages/HomePage.tsx @@ -1,4 +1,4 @@ -import { useCallback, useRef, useState } from 'react' +import { useRef, useState } from 'react' import { PostsService } from '../posts/postsService.ts' import { useUser } from '../../user/user.ts' import { MediaService } from '../../media/mediaService.ts' @@ -11,6 +11,7 @@ import { Post } from '../posts/posts.ts' import { produce, WritableDraft } from 'immer' import PostItem from '../components/PostItem.tsx' import { useIntersectionLoad } from '../../../hooks/useIntersectionLoad.ts' +import { delay } from '../../../utils/delay.ts' interface HomePageProps { postsService: PostsService @@ -24,13 +25,6 @@ export default function HomePage({ postsService, mediaService }: HomePageProps) useSaveSignupCodeToLocalStorage() const [isSubmitting, setIsSubmitting] = useState(false) - const fetchPosts = useCallback( - async (cursor: string | null, amount: number | null) => { - return postsService.loadPublicFeed(cursor, amount) - }, - [postsService], - ) - const [posts, setPosts] = useState([]) const [hasMore, setHasMore] = useState(true) const [error, setError] = useState(null) @@ -38,56 +32,54 @@ export default function HomePage({ postsService, mediaService }: HomePageProps) const cursor = useRef(null) const loading = useRef(false) - const loadNextPage = useCallback(async () => { + const loadNextPage = async () => { if (loading.current || !hasMore || error) return loading.current = true try { - const delay = new Promise((resolve) => setTimeout(resolve, 500)) - const pagePromise = fetchPosts(cursor.current, PageSize) - const [page] = await Promise.all([pagePromise, delay]) - setHasMore(page.length >= PageSize) - cursor.current = page.at(-1)?.postId ?? null - setPosts((prev) => [...prev, ...page]) + const [{ posts, next }] = await Promise.all([ + postsService.loadPublicFeed(cursor.current, PageSize), + delay(500), + ]) + + setHasMore(posts.length >= PageSize) + cursor.current = next + setPosts((prev) => [...prev, ...posts]) } catch (e: unknown) { - const err = e as Error - setError(err.message) + setError((e as Error).message) } finally { loading.current = false } - }, [fetchPosts, hasMore, error]) + } - const onCreatePost = useCallback( - async ( - content: string, - files: { file: File; width: number; height: number }[], - isPublic: boolean, - ) => { - setIsSubmitting(true) - if (user == null) throw new Error('Not logged in') - try { - const media = await Promise.all( - files.map(async ({ file, width, height }) => { - const { mediaId, url } = await mediaService.uploadImage(file) + const onCreatePost = async ( + content: string, + files: { file: File; width: number; height: number }[], + isPublic: boolean, + ) => { + setIsSubmitting(true) + if (user == null) throw new Error('Not logged in') + try { + const media = await Promise.all( + files.map(async ({ file, width, height }) => { + const { mediaId, url } = await mediaService.uploadImage(file) - return { - mediaId, - url, - width, - height, - } - }), - ) - const post = await postsService.createNew(user.id, content, media, isPublic) - setPosts((pages) => [post, ...pages]) - } catch (error) { - console.error('Failed to create post:', error) - } finally { - setIsSubmitting(false) - } - }, - [mediaService, postsService, setPosts, user], - ) + return { + mediaId, + url, + width, + height, + } + }), + ) + const post = await postsService.createNew(user.id, content, media, isPublic) + setPosts((pages) => [post, ...pages]) + } catch (error) { + console.error('Failed to create post:', error) + } finally { + setIsSubmitting(false) + } + } const isLoggedIn = user != null diff --git a/src/app/feed/posts/postsService.ts b/src/app/feed/posts/postsService.ts index e6c2c88..06fa2ff 100644 --- a/src/app/feed/posts/postsService.ts +++ b/src/app/feed/posts/postsService.ts @@ -29,34 +29,22 @@ export class PostsService { return Post.fromDto(response.data.post) } - async loadPublicFeed(cursor: string | null, amount: number | null): Promise { - const response = await this.client.GET('/posts', { - query: { cursor, amount }, - credentials: 'include', - }) - - if (!response.data) { - return [] - } - - return response.data?.posts.map((post) => Post.fromDto(post)) - } - - async loadByAuthor( - username: string, + async loadPublicFeed( cursor: string | null, amount: number | null, - ): Promise { + ): Promise<{ posts: Post[]; next: string | null }> { const response = await this.client.GET('/posts', { - query: { From: cursor ?? undefined, Amount: amount ?? undefined, Author: username }, + params: { + query: { From: cursor ?? undefined, Amount: amount ?? undefined }, + }, credentials: 'include', }) if (!response.data) { - return [] + return { posts: [], next: null } } - return response.data?.posts.map((post) => Post.fromDto(post)) + return { posts: response.data.posts.map(Post.fromDto), next: response.data.next } } async addReaction(postId: string, emoji: string): Promise { diff --git a/src/utils/delay.ts b/src/utils/delay.ts new file mode 100644 index 0000000..9c70749 --- /dev/null +++ b/src/utils/delay.ts @@ -0,0 +1,3 @@ +export function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +}