@@ -21,6 +21,7 @@ import {
21
21
useQuery ,
22
22
} from '@apollo/client' ;
23
23
import { OperationVariables } from '@apollo/client/core' ;
24
+ import { useState } from 'react' ;
24
25
import {
25
26
BackupValidationResult ,
26
27
ICategory ,
@@ -58,6 +59,9 @@ import {
58
59
EnqueueChapterDownloadMutationVariables ,
59
60
EnqueueChapterDownloadsMutation ,
60
61
EnqueueChapterDownloadsMutationVariables ,
62
+ FetchSourceMangaInput ,
63
+ FetchSourceMangaType ,
64
+ FilterChangeInput ,
61
65
GetAboutQuery ,
62
66
GetAboutQueryVariables ,
63
67
GetExtensionsFetchMutation ,
@@ -74,6 +78,8 @@ import {
74
78
GetMangaFetchMutationVariables ,
75
79
GetMangaQuery ,
76
80
GetMangaQueryVariables ,
81
+ GetSourceMangasFetchMutation ,
82
+ GetSourceMangasFetchMutationVariables ,
77
83
GetSourceQuery ,
78
84
GetSourceQueryVariables ,
79
85
GetSourcesQuery ,
@@ -214,6 +220,13 @@ type AbortableApolloUseMutationResponse<Data = any, Variables extends OperationV
214
220
MutationTuple < Data , Variables > [ 0 ] ,
215
221
MutationTuple < Data , Variables > [ 1 ] & AbortableRequest ,
216
222
] ;
223
+ type AbortableApolloUseMutationPaginatedResponse <
224
+ Data = any ,
225
+ Variables extends OperationVariables = OperationVariables ,
226
+ > = [
227
+ ( page : number ) => Promise < FetchResult < Data > > ,
228
+ ( MutationTuple < Data , Variables > [ 1 ] & AbortableRequest & { size : number ; loadingMore : boolean } ) [ ] ,
229
+ ] ;
217
230
type AbortableApolloMutationResponse < Data = any > = { response : Promise < FetchResult < Data > > } & AbortableRequest ;
218
231
219
232
const isLoadingMore = ( swrResult : SWRInfiniteResponse ) : boolean => {
@@ -625,6 +638,99 @@ export class RequestManager {
625
638
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_SOURCE , { id } , options ) ;
626
639
}
627
640
641
+ public useGetSourceMangas (
642
+ input : FetchSourceMangaInput ,
643
+ options ?: MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > ,
644
+ ) : AbortableApolloUseMutationPaginatedResponse <
645
+ GetSourceMangasFetchMutation ,
646
+ GetSourceMangasFetchMutationVariables
647
+ > {
648
+ const createPaginatedResult = (
649
+ result : AbortableApolloUseMutationResponse [ 1 ] ,
650
+ page : number ,
651
+ ) : AbortableApolloUseMutationPaginatedResponse [ 1 ] [ number ] => {
652
+ const loading = result . loading || ! result . called ;
653
+ return {
654
+ ...result ,
655
+ loading,
656
+ size : page ,
657
+ loadingMore : loading && page > 1 ,
658
+ } ;
659
+ } ;
660
+
661
+ // TODO - implement caching
662
+ // - ? global cache with revalidating (same as SWR does, revalidate each page starting with 1st until the first page is reached whose data didn't change)
663
+ // - ? saving fetched mangas in location state and only "cache" when navigating prev/next
664
+ const [ mutate , result ] = this . doRequestNew < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > (
665
+ GQLMethod . USE_MUTATION ,
666
+ GET_SOURCE_MANGAS_FETCH ,
667
+ { input } ,
668
+ options ,
669
+ ) ;
670
+
671
+ const [ previousResults , setPreviousResults ] = useState < AbortableApolloUseMutationPaginatedResponse [ 1 ] > ( [
672
+ createPaginatedResult ( result , input . page ) ,
673
+ ] ) ;
674
+
675
+ const [ contentType , setContentType ] = useState ( input . type ) ;
676
+ const [ query , setQuery ] = useState ( input . query ) ;
677
+ const [ page , setPage ] = useState ( input . page ) ;
678
+
679
+ const paginatedResult = createPaginatedResult ( result , page ) ;
680
+
681
+ // TODO - option "global cache with revalidating"
682
+ // replace previousResults with cache
683
+ // cache specific response
684
+ // cache "base" key to specific page keys to be able to retrieve all necessary cached pages
685
+ // get cached results
686
+ // revalidate in background - revalidate first page -> result changed? revalidate every page until cached result and response is the same
687
+
688
+ // wrap "mutate" function to align with the expected type, which allows only passing a "page" argument
689
+ const wrappedMutate = ( newPage : number ) => {
690
+ const resetPreviousResultForInitialLoad = newPage < page ;
691
+ if ( resetPreviousResultForInitialLoad ) {
692
+ setPreviousResults ( previousResults . filter ( ( prevResult ) => prevResult . size <= newPage ) ) ;
693
+ }
694
+
695
+ if ( newPage !== page ) {
696
+ setPage ( newPage ) ;
697
+ }
698
+
699
+ return mutate ( {
700
+ variables : {
701
+ input : {
702
+ ...input ,
703
+ page : newPage ,
704
+ } ,
705
+ } ,
706
+ } ) ;
707
+ } ;
708
+
709
+ const contentTypeChanged = contentType !== input . type ;
710
+ const queryChanged = query !== input . query ;
711
+ // instantly return empty results in case the provided variables changed - wait until the hook returns empty data,
712
+ // otherwise, updating the previous results will revert the reset
713
+ const resetPreviousResult = ( queryChanged || contentTypeChanged ) && ! paginatedResult . data ;
714
+ let updatedResults = [
715
+ ...( resetPreviousResult ? [ { ...paginatedResult , size : page , loadingMore : false } ] : previousResults ) ,
716
+ ] ;
717
+
718
+ if ( resetPreviousResult ) {
719
+ setContentType ( input . type ) ;
720
+ setQuery ( input . query ) ;
721
+ setPreviousResults ( [ paginatedResult ] ) ;
722
+ }
723
+
724
+ const resultChanged = previousResults [ page - 1 ] ?. loading !== paginatedResult . loading ;
725
+ const updatePreviousResult = resultChanged && ! resetPreviousResult ;
726
+ if ( updatePreviousResult ) {
727
+ updatedResults = [ ...previousResults . slice ( 0 , page - 1 ) , paginatedResult ] ;
728
+ setPreviousResults ( updatedResults ) ;
729
+ }
730
+
731
+ return [ wrappedMutate , updatedResult ] ;
732
+ }
733
+
628
734
public useGetSourcePopularMangas (
629
735
sourceId : string ,
630
736
initialPages ?: number ,
@@ -683,21 +789,15 @@ export class RequestManager {
683
789
}
684
790
685
791
public useSourceSearch (
686
- sourceId : string ,
687
- searchTerm : string ,
688
- initialPages ?: number ,
689
- swrOptions ?: SWRInfiniteOptions < SourceSearchResult > ,
690
- ) : AbortableSWRInfiniteResponse < SourceSearchResult > {
691
- return this . doRequest ( HttpMethod . SWR_GET_INFINITE , '' , {
692
- swrOptions : {
693
- getEndpoint : ( page , previousData ) =>
694
- previousData ?. hasNextPage ?? true
695
- ? `source/${ sourceId } /search?searchTerm=${ searchTerm } &pageNum=${ page + 1 } `
696
- : null ,
697
- initialSize : initialPages ,
698
- ...swrOptions ,
699
- } as typeof swrOptions ,
700
- } ) ;
792
+ source : string ,
793
+ query : string ,
794
+ filters ?: FilterChangeInput [ ] ,
795
+ options ?: MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > ,
796
+ ) : AbortableApolloUseMutationPaginatedResponse <
797
+ GetSourceMangasFetchMutation ,
798
+ GetSourceMangasFetchMutationVariables
799
+ > {
800
+ return this . useGetSourceMangas ( { type : FetchSourceMangaType . Search , source, query, filters, page : 1 } , options ) ;
701
801
}
702
802
703
803
public useSourceQuickSearch (
0 commit comments