1
1
import { Suspense } from "react" ;
2
2
3
+ import type { ProcessedPub } from "contracts" ;
3
4
import type { CommunitiesId , UsersId } from "db/public" ;
4
5
import { Skeleton } from "ui/skeleton" ;
5
6
import { cn } from "utils" ;
6
7
7
8
import { searchParamsCache } from "~/app/components/DataTable/PubsDataTable/validations" ;
8
9
import { FooterPagination } from "~/app/components/Pagination" ;
9
10
import { PubCard } from "~/app/components/PubCard" ;
10
- import { getStageActions } from "~/lib/db/queries" ;
11
11
import { getPubsCount , getPubsWithRelatedValues } from "~/lib/server" ;
12
12
import { getCommunitySlug } from "~/lib/server/cache/getCommunitySlug" ;
13
13
import { getStages } from "~/lib/server/stages" ;
14
- import { PubSelector } from "./PubSelector " ;
14
+ import { PubSearch } from "./PubSearchInput " ;
15
15
import { PubsSelectedProvider } from "./PubsSelectedContext" ;
16
16
import { PubsSelectedCounter } from "./PubsSelectedCounter" ;
17
17
@@ -27,56 +27,46 @@ type PaginatedPubListProps = {
27
27
userId : UsersId ;
28
28
} ;
29
29
30
- const PaginatedPubListInner = async ( props : PaginatedPubListProps ) => {
31
- const search = searchParamsCache . parse ( props . searchParams ) ;
32
- const [ count , pubs , stages , actions ] = await Promise . all ( [
33
- getPubsCount ( { communityId : props . communityId } ) ,
34
- getPubsWithRelatedValues (
30
+ type PubListProcessedPub = ProcessedPub < {
31
+ withPubType : true ;
32
+ withRelatedPubs : false ;
33
+ withStage : true ;
34
+ withRelatedCounts : true ;
35
+ } > ;
36
+
37
+ const PaginatedPubListInner = async (
38
+ props : PaginatedPubListProps & {
39
+ communitySlug : string ;
40
+ pubsPromise : Promise < PubListProcessedPub [ ] > ;
41
+ }
42
+ ) => {
43
+ const [ pubs , stages ] = await Promise . all ( [
44
+ props . pubsPromise ,
45
+ getStages (
35
46
{ communityId : props . communityId , userId : props . userId } ,
36
- {
37
- limit : search . perPage ,
38
- offset : ( search . page - 1 ) * search . perPage ,
39
- orderBy : "updatedAt" ,
40
- withPubType : true ,
41
- withRelatedPubs : false ,
42
- withStage : true ,
43
- withValues : false ,
44
- withRelatedCounts : true ,
45
- }
46
- ) ,
47
- getStages ( { communityId : props . communityId , userId : props . userId } ) . execute ( ) ,
48
- getStageActions ( { communityId : props . communityId } ) . execute ( ) ,
47
+ { withActionInstances : "full" }
48
+ ) . execute ( ) ,
49
49
] ) ;
50
50
51
- const totalPages = Math . ceil ( count / search . perPage ) ;
52
-
53
- const communitySlug = await getCommunitySlug ( ) ;
54
- const basePath = props . basePath ?? `/c/${ communitySlug } /pubs` ;
55
-
56
51
return (
57
- < div className = { cn ( "flex flex-col gap-8" ) } >
58
- < PubsSelectedProvider pubIds = { [ ] } >
52
+ < PubsSelectedProvider pubIds = { [ ] } >
53
+ < div className = "mr-auto flex flex-col gap-3 md:max-w-screen-lg" >
59
54
{ pubs . map ( ( pub ) => {
55
+ const stageForPub = stages . find ( ( stage ) => stage . id === pub . stage ?. id ) ;
56
+
60
57
return (
61
58
< PubCard
62
59
key = { pub . id }
63
60
pub = { pub }
64
- communitySlug = { communitySlug }
65
- stages = { stages }
66
- actionInstances = { actions }
61
+ communitySlug = { props . communitySlug }
62
+ moveFrom = { stageForPub ?. moveConstraintSources }
63
+ moveTo = { stageForPub ?. moveConstraints }
64
+ actionInstances = { stageForPub ?. actionInstances }
67
65
/>
68
66
) ;
69
67
} ) }
70
- < FooterPagination
71
- basePath = { basePath }
72
- searchParams = { props . searchParams }
73
- page = { search . page }
74
- totalPages = { totalPages }
75
- >
76
- < PubsSelectedCounter pageSize = { search . perPage } />
77
- </ FooterPagination >
78
- </ PubsSelectedProvider >
79
- </ div >
68
+ </ div >
69
+ </ PubsSelectedProvider >
80
70
) ;
81
71
} ;
82
72
@@ -87,7 +77,7 @@ export const PubListSkeleton = ({
87
77
amount ?: number ;
88
78
className ?: string ;
89
79
} ) => (
90
- < div className = { cn ( [ "flex flex-col gap-8 " , className ] ) } >
80
+ < div className = { cn ( [ "flex flex-col gap-3 " , className ] ) } >
91
81
{ Array . from ( { length : amount } ) . map ( ( _ , index ) => (
92
82
< Skeleton key = { index } className = "flex h-[90px] w-full flex-col gap-2 px-4 py-3" >
93
83
< Skeleton className = "mt-3 h-6 w-24 space-y-1.5" />
@@ -97,10 +87,89 @@ export const PubListSkeleton = ({
97
87
</ div >
98
88
) ;
99
89
90
+ const PubListFooterPagination = async ( props : {
91
+ basePath : string ;
92
+ searchParams : Record < string , unknown > ;
93
+ page : number ;
94
+ communityId : CommunitiesId ;
95
+ children : React . ReactNode ;
96
+ pubsPromise : Promise < ProcessedPub [ ] > ;
97
+ } ) => {
98
+ const perPage = searchParamsCache . get ( "perPage" ) ;
99
+ const isQuery = ! ! searchParamsCache . get ( "query" ) ;
100
+
101
+ const count = await ( isQuery
102
+ ? props . pubsPromise . then ( ( pubs ) => pubs . length )
103
+ : getPubsCount ( { communityId : props . communityId } ) ) ;
104
+
105
+ const paginationProps = isQuery
106
+ ? {
107
+ mode : "cursor" as const ,
108
+ hasNextPage : count > perPage ,
109
+ }
110
+ : {
111
+ mode : "total" as const ,
112
+ totalPages : Math . ceil ( ( count ?? 0 ) / perPage ) ,
113
+ } ;
114
+
115
+ return (
116
+ < FooterPagination { ...props } { ...paginationProps } className = "z-20" >
117
+ { props . children }
118
+ </ FooterPagination >
119
+ ) ;
120
+ } ;
121
+
100
122
export const PaginatedPubList : React . FC < PaginatedPubListProps > = async ( props ) => {
123
+ const search = searchParamsCache . parse ( props . searchParams ) ;
124
+
125
+ const communitySlug = await getCommunitySlug ( ) ;
126
+
127
+ const basePath = props . basePath ?? `/c/${ communitySlug } /pubs` ;
128
+
129
+ // we do one more than the total amount of pubs to know if there is a next page
130
+ const limit = search . query ? search . perPage + 1 : search . perPage ;
131
+
132
+ const pubsPromise = getPubsWithRelatedValues (
133
+ { communityId : props . communityId , userId : props . userId } ,
134
+ {
135
+ limit,
136
+ offset : ( search . page - 1 ) * search . perPage ,
137
+ orderBy : "updatedAt" ,
138
+ withPubType : true ,
139
+ withRelatedPubs : false ,
140
+ withStage : true ,
141
+ withValues : false ,
142
+ withRelatedCounts : true ,
143
+ search : search . query ,
144
+ }
145
+ ) ;
146
+
101
147
return (
102
- < Suspense fallback = { < PubListSkeleton /> } >
103
- < PaginatedPubListInner { ...props } />
104
- </ Suspense >
148
+ < div className = "relative flex h-full flex-col" >
149
+ < div
150
+ className = { cn ( "mb-4 flex h-full w-full flex-col gap-3 overflow-y-scroll p-4 pb-16" ) }
151
+ >
152
+ < PubSearch >
153
+ < Suspense fallback = { < PubListSkeleton /> } >
154
+ < PaginatedPubListInner
155
+ { ...props }
156
+ communitySlug = { communitySlug }
157
+ pubsPromise = { pubsPromise }
158
+ />
159
+ </ Suspense >
160
+ </ PubSearch >
161
+ </ div >
162
+ < Suspense fallback = { null } >
163
+ < PubListFooterPagination
164
+ basePath = { basePath }
165
+ searchParams = { props . searchParams }
166
+ page = { search . page }
167
+ communityId = { props . communityId }
168
+ pubsPromise = { pubsPromise }
169
+ >
170
+ < PubsSelectedCounter pageSize = { search . perPage } />
171
+ </ PubListFooterPagination >
172
+ </ Suspense >
173
+ </ div >
105
174
) ;
106
175
} ;
0 commit comments