11import { useState , useMemo } from "react" ;
22import { useQuery , useMutation , useQueryClient } from "@tanstack/react-query" ;
33import { Button } from "@/components/ui/button" ;
4- import { Plus , BookOpen , Star , Clock } from "lucide-react" ;
4+ import { Plus , BookOpen , Star } from "lucide-react" ;
55import PaperCard from "@/components/PaperCard" ;
66import { Link } from "react-router-dom" ;
77import { useAuth } from "@/contexts/AuthContext" ;
@@ -13,14 +13,15 @@ import DashboardHeader from "./components/DashboardHeader";
1313import SearchAndFilter from "./components/SearchAndFilter" ;
1414import { CreatePaperRequest } from "@/types/paper.types" ;
1515import { getWorkflowsByUser } from "@/services/progress.service" ;
16- import { supabase } from "@/integrations/supabase/client" ;
1716import { Tabs , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
17+ import { supabase } from "@/integrations/supabase/client" ;
18+
1819
1920const Dashboard = ( ) => {
2021 const { user } = useAuth ( ) ;
2122 const queryClient = useQueryClient ( ) ;
2223 const [ isImportOpen , setIsImportOpen ] = useState ( false ) ;
23- const [ activeTab , setActiveTab ] = useState < 'all' | 'recently_read' | ' favourites'> ( 'all' ) ;
24+ const [ activeTab , setActiveTab ] = useState < 'all' | 'favourites' > ( 'all' ) ;
2425 const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
2526 const [ newPaper , setNewPaper ] = useState ( {
2627 authors : '' ,
@@ -55,7 +56,7 @@ const Dashboard = () => {
5556 // Apply search filter if provided
5657 if ( searchQuery ) {
5758 const searchLower = searchQuery . toLowerCase ( ) ;
58- favorites = favorites . filter ( ( paper ) =>
59+ favorites = favorites . filter ( ( paper : any ) =>
5960 paper . title ?. toLowerCase ( ) . includes ( searchLower ) ||
6061 paper . authors ?. toLowerCase ( ) . includes ( searchLower ) ||
6162 paper . journal ?. toLowerCase ( ) . includes ( searchLower )
@@ -64,22 +65,22 @@ const Dashboard = () => {
6465
6566 // Apply filters
6667 if ( filters . author ) {
67- favorites = favorites . filter ( ( paper ) =>
68+ favorites = favorites . filter ( ( paper : any ) =>
6869 paper . authors ?. toLowerCase ( ) . includes ( filters . author . toLowerCase ( ) )
6970 ) ;
7071 }
7172 if ( filters . journal ) {
72- favorites = favorites . filter ( ( paper ) =>
73+ favorites = favorites . filter ( ( paper : any ) =>
7374 paper . journal ?. toLowerCase ( ) . includes ( filters . journal . toLowerCase ( ) )
7475 ) ;
7576 }
7677 if ( filters . yearFrom ) {
77- favorites = favorites . filter ( ( paper ) =>
78+ favorites = favorites . filter ( ( paper : any ) =>
7879 paper . publicationYear >= parseInt ( filters . yearFrom )
7980 ) ;
8081 }
8182 if ( filters . yearTo ) {
82- favorites = favorites . filter ( ( paper ) =>
83+ favorites = favorites . filter ( ( paper : any ) =>
8384 paper . publicationYear <= parseInt ( filters . yearTo )
8485 ) ;
8586 }
@@ -97,68 +98,6 @@ const Dashboard = () => {
9798 totalPages : Math . max ( 1 , Math . ceil ( favorites . length / pageSize ) ) ,
9899 } ,
99100 } ;
100- } else if ( activeTab === 'recently_read' ) {
101- // Fetch from Supabase for recently read
102- let query = supabase
103- . from ( 'papers' )
104- . select ( '*' )
105- . eq ( 'user_id' , user ! . id )
106- . gt ( 'last_read_page' , 0 ) ;
107-
108- // Apply search filter if provided
109- if ( searchQuery ) {
110- query = query . or ( `title.ilike.%${ searchQuery } %,journal.ilike.%${ searchQuery } %` ) ;
111- }
112-
113- // Apply filters
114- if ( filters . author ) {
115- query = query . contains ( 'authors' , [ filters . author ] ) ;
116- }
117- if ( filters . journal ) {
118- query = query . ilike ( 'journal' , `%${ filters . journal } %` ) ;
119- }
120- if ( filters . yearFrom ) {
121- query = query . gte ( 'year' , parseInt ( filters . yearFrom ) ) ;
122- }
123- if ( filters . yearTo ) {
124- query = query . lte ( 'year' , parseInt ( filters . yearTo ) ) ;
125- }
126-
127- query = query . order ( 'updated_at' , { ascending : false } ) ;
128-
129- const { data : supabasePapers , error : supabaseError } = await query ;
130-
131- if ( supabaseError ) throw supabaseError ;
132-
133- // Transform Supabase papers to match API format
134- const transformedPapers = ( supabasePapers || [ ] ) . map ( ( paper ) => ( {
135- id : paper . id ,
136- title : paper . title ,
137- authors : Array . isArray ( paper . authors ) ? paper . authors . join ( ', ' ) : paper . authors ,
138- journal : paper . journal || '' ,
139- publicationYear : paper . year ,
140- doi : paper . doi || '' ,
141- description : paper . abstract || '' ,
142- keywords : paper . keywords || [ ] ,
143- status : paper . status || null ,
144- priority : paper . priority || null ,
145- isFavorite : false , // Not from backend, so default to false
146- last_read_page : paper . last_read_page || 0 ,
147- } ) ) ;
148-
149- // Client-side pagination
150- const startIndex = ( page - 1 ) * pageSize ;
151- const endIndex = startIndex + pageSize ;
152- const paginatedPapers = transformedPapers . slice ( startIndex , endIndex ) ;
153-
154- return {
155- status : 200 ,
156- data : {
157- papers : paginatedPapers ,
158- totalElements : transformedPapers . length ,
159- totalPages : Math . max ( 1 , Math . ceil ( transformedPapers . length / pageSize ) ) ,
160- } ,
161- } ;
162101 } else {
163102 // Use existing API for 'all' tab
164103 return await getPaginatedPapers ( page , pageSize , searchQuery , filters , user ?. id ) ;
@@ -194,20 +133,66 @@ const Dashboard = () => {
194133
195134 // Enhance papers with workflow data
196135 const papersWithProgress = useMemo ( ( ) => {
197- return papers . map ( paper => {
198- const workflow = workflowMap . get ( paper . id ) ;
199- // Calculate total_pages from progress if available
200- let total_pages = null ;
201- if ( workflow && workflow . progress > 0 && workflow . lastPage > 0 ) {
202- total_pages = Math . ceil ( ( workflow . lastPage / ( workflow . progress / 100 ) ) ) ;
136+ let processedPapers = papers . map ( paper => {
137+ // Helper function to decode base64 encoded ID
138+ const decodeId = ( encodedId : string ) : string => {
139+ try {
140+ if ( / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } $ / i. test ( encodedId ) ) {
141+ return encodedId ;
142+ }
143+ return atob ( encodedId ) ;
144+ } catch ( e ) {
145+ return encodedId ;
146+ }
147+ } ;
148+
149+ // Try to find workflow by matching decoded paperId
150+ let workflow = null ;
151+ if ( workflows ) {
152+ workflow = workflows . find ( w => {
153+ const decodedWorkflowPaperId = decodeId ( w . paperId ) ;
154+ return decodedWorkflowPaperId === paper . id || w . paperId === paper . id ;
155+ } ) ;
156+ }
157+
158+ // If not found in workflows array, try workflowMap (might have different key format)
159+ if ( ! workflow ) {
160+ workflow = workflowMap . get ( paper . id ) ;
161+ // Also try with encoded paper.id
162+ if ( ! workflow ) {
163+ const encodedPaperId = btoa ( paper . id ) ;
164+ workflow = workflowMap . get ( encodedPaperId ) ;
165+ }
166+ }
167+
168+ // Use workflow data if available, otherwise use paper data
169+ let last_read_page = paper . last_read_page ;
170+ let total_pages = paper . total_pages || null ;
171+ let progress = paper . progress || null ;
172+
173+ if ( workflow ) {
174+ // Prefer workflow data
175+ last_read_page = workflow . lastPage || paper . last_read_page || null ;
176+ progress = workflow . progress || paper . progress || null ;
177+
178+ // Calculate total_pages from progress if available
179+ if ( workflow . progress > 0 && workflow . lastPage > 0 ) {
180+ total_pages = Math . ceil ( ( workflow . lastPage / ( workflow . progress / 100 ) ) ) ;
181+ } else if ( ! total_pages && last_read_page && last_read_page > 0 ) {
182+ // If we have last_read_page but no progress, estimate total_pages
183+ total_pages = null ; // Keep null if we can't calculate accurately
184+ }
203185 }
204186 return {
205187 ...paper ,
206- last_read_page : workflow ?. lastPage ?? null ,
188+ last_read_page : last_read_page ,
207189 total_pages : total_pages ,
190+ progress : progress ,
208191 } ;
209192 } ) ;
210- } , [ papers , workflowMap ] ) ;
193+
194+ return processedPapers ;
195+ } , [ papers , workflowMap , activeTab , workflows ] ) ;
211196
212197 const importMutation = useMutation ( {
213198 mutationFn : async ( ) => {
@@ -285,15 +270,11 @@ const Dashboard = () => {
285270
286271 { /* Tabs */ }
287272 < Tabs value = { activeTab } onValueChange = { ( v ) => {
288- setActiveTab ( v as 'all' | 'recently_read' | ' favourites') ;
273+ setActiveTab ( v as 'all' | 'favourites' ) ;
289274 setPage ( 1 ) ; // Reset to first page when switching tabs
290275 } } >
291- < TabsList className = "grid w-full grid-cols-3 " >
276+ < TabsList className = "grid w-full grid-cols-2 " >
292277 < TabsTrigger value = "all" > All Papers</ TabsTrigger >
293- < TabsTrigger value = "recently_read" >
294- < Clock className = "h-4 w-4 mr-2" />
295- Recently Read
296- </ TabsTrigger >
297278 < TabsTrigger value = "favourites" >
298279 < Star className = "h-4 w-4 mr-2" />
299280 Favourites
@@ -330,18 +311,14 @@ const Dashboard = () => {
330311 < BookOpen className = "h-12 w-12 mx-auto mb-4 text-muted-foreground" />
331312 < h3 className = "text-lg font-semibold mb-2" >
332313 { activeTab === 'favourites'
333- ? 'No favourite papers yet'
334- : activeTab === 'recently_read'
335- ? 'No recently read papers'
314+ ? 'No favourite papers yet'
336315 : 'No papers yet' }
337316 </ h3 >
338317 < p className = "text-muted-foreground mb-4" >
339318 { searchQuery
340319 ? 'No papers found matching your search'
341320 : activeTab === 'favourites'
342321 ? 'Mark papers as favourites to see them here'
343- : activeTab === 'recently_read'
344- ? 'Papers you\'ve read will appear here'
345322 : 'Import your first paper to get started' }
346323 </ p >
347324 { ! searchQuery && activeTab === 'all' && (
0 commit comments