From b5a8357d924ca95c1244215b8c09d5b8a1e5aca4 Mon Sep 17 00:00:00 2001 From: alok-108 Date: Tue, 24 Mar 2026 13:09:57 +0530 Subject: [PATCH] Fix: standardize loading and error handling in papers page --- src/app/(main)/(articles)/articles/page.tsx | 144 +++++++++++--------- 1 file changed, 83 insertions(+), 61 deletions(-) diff --git a/src/app/(main)/(articles)/articles/page.tsx b/src/app/(main)/(articles)/articles/page.tsx index 7b7ac277..a61ae17c 100644 --- a/src/app/(main)/(articles)/articles/page.tsx +++ b/src/app/(main)/(articles)/articles/page.tsx @@ -5,17 +5,14 @@ import React, { useCallback, useEffect, useState } from 'react'; import { FileX2 } from 'lucide-react'; import { useMediaQuery } from 'usehooks-ts'; -import { useArticlesApiGetArticles } from '@/api/articles/articles'; import { ArticlesListOut } from '@/api/schemas'; -import { useUsersApiListMyArticles } from '@/api/users/users'; import ArticleCard, { ArticleCardSkeleton } from '@/components/articles/ArticleCard'; import ArticlePreviewSection from '@/components/articles/ArticlePreviewSection'; import SearchableList, { LoadingType } from '@/components/common/SearchableList'; import TabComponent from '@/components/communities/TabComponent'; import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'; -import { FIVE_MINUTES_IN_MS, SCREEN_WIDTH_SM } from '@/constants/common.constants'; +import { SCREEN_WIDTH_SM } from '@/constants/common.constants'; import { useKeyboardNavigation } from '@/hooks/useKeyboardNavigation'; -import { showErrorToast } from '@/lib/toastHelpers'; import { cn } from '@/lib/utils'; import { useArticlesViewStore } from '@/stores/articlesViewStore'; import { useAuthStore } from '@/stores/authStore'; @@ -106,21 +103,9 @@ const TabContent: React.FC = ({ : undefined, }); - const { data, isPending, error } = useArticlesApiGetArticles( - { - page, - per_page: 50, - search, - }, - { - query: { - staleTime: FIVE_MINUTES_IN_MS, - refetchOnWindowFocus: true, - queryKey: ['articles', page, search], - enabled: isActive, - }, - } - ); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [data, setData] = useState([]); useEffect(() => { if (!isDesktop && viewType === 'preview') { @@ -129,19 +114,35 @@ const TabContent: React.FC = ({ }, [isDesktop, viewType]); useEffect(() => { - if (error) { - showErrorToast(error); - } - if (data) { - if (page === 1) { - setArticles(data.data.items); - } else { - setArticles((prevArticles) => [...prevArticles, ...data.data.items]); + const fetchArticles = async () => { + if (!isActive) return; + try { + setLoading(true); + setError(null); + + const API_URL = `${process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'}/api/v1/articles?page=${page}&per_page=50&search=${search}`; + const response = await fetch(API_URL); + if (!response.ok) throw new Error('Failed to load data'); + const result = await response.json(); + + setData(result.data?.items || []); + + if (page === 1) { + setArticles(result.data?.items || []); + } else { + setArticles((prevArticles) => [...prevArticles, ...(result.data?.items || [])]); + } + setTotalItems(result.data?.total || 0); + setTotalPages(result.data?.num_pages || 1); + } catch (err) { + setError('Failed to load data'); + } finally { + setLoading(false); } - setTotalItems(data.data.total); - setTotalPages(data.data.num_pages); - } - }, [data, error, page, loadingType]); + }; + + fetchArticles(); + }, [page, search, isActive, loadingType]); const handleSearch = useCallback( (term: string) => { @@ -182,6 +183,14 @@ const TabContent: React.FC = ({ ); const renderSkeleton = useCallback(() => , []); + if (loading && page === 1) { + return

Loading...

; + } + + if (error) { + return

{error}

; + } + return (
= ({ onLoadMore={handleLoadMore} renderItem={renderArticle} renderSkeleton={renderSkeleton} - isLoading={isPending} + isLoading={loading} items={articles} totalItems={totalItems} totalPages={totalPages} @@ -319,22 +328,9 @@ const MyArticlesTabContent: React.FC = ({ : undefined, }); - const { data, isPending, error } = useUsersApiListMyArticles( - { - page, - per_page: 50, - search, - }, - { - query: { - staleTime: FIVE_MINUTES_IN_MS, - refetchOnWindowFocus: true, - queryKey: ['my_articles', page, search], - enabled: isActive, - }, - request: { headers: { Authorization: `Bearer ${accessToken}` } }, - } - ); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [data, setData] = useState([]); useEffect(() => { if (!isDesktop && viewType === 'preview') { @@ -343,19 +339,37 @@ const MyArticlesTabContent: React.FC = ({ }, [isDesktop, viewType]); useEffect(() => { - if (error) { - showErrorToast(error); - } - if (data) { - if (page === 1) { - setArticles(data.data.items); - } else { - setArticles((prevArticles) => [...prevArticles, ...data.data.items]); + const fetchArticles = async () => { + if (!isActive) return; + try { + setLoading(true); + setError(null); + + const API_URL = `${process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'}/api/v1/users/me_articles?page=${page}&per_page=50&search=${search}`; + const response = await fetch(API_URL, { + headers: { Authorization: `Bearer ${accessToken}` }, + }); + if (!response.ok) throw new Error('Failed to load data'); + const result = await response.json(); + + setData(result.data?.items || []); + + if (page === 1) { + setArticles(result.data?.items || []); + } else { + setArticles((prevArticles) => [...prevArticles, ...(result.data?.items || [])]); + } + setTotalItems(result.data?.total || 0); + setTotalPages(result.data?.num_pages || 1); + } catch (err) { + setError('Failed to load data'); + } finally { + setLoading(false); } - setTotalItems(data.data.total); - setTotalPages(data.data.num_pages); - } - }, [data, error, page, loadingType]); + }; + + fetchArticles(); + }, [page, search, isActive, loadingType]); const handleSearch = useCallback( (term: string) => { @@ -396,6 +410,14 @@ const MyArticlesTabContent: React.FC = ({ ); const renderSkeleton = useCallback(() => , []); + if (loading && page === 1) { + return

Loading...

; + } + + if (error) { + return

{error}

; + } + return (
= ({ onLoadMore={handleLoadMore} renderItem={renderArticle} renderSkeleton={renderSkeleton} - isLoading={isPending} + isLoading={loading} items={articles} totalItems={totalItems} totalPages={totalPages}