1- import React , { useState } from "react" ;
1+ import React , { useEffect , useState } from "react" ;
22import {
33 FlatList ,
44 RefreshControl ,
88} from "react-native" ;
99import { SafeAreaView } from "react-native-safe-area-context" ;
1010import { Stack , useRouter } from "expo-router" ;
11+ import { MaterialIcons } from "@expo/vector-icons" ;
1112
1213import Discussion from "~/components/Discussion" ;
1314import FloatingButton from "~/components/FloatingButton" ;
@@ -19,31 +20,117 @@ import RedDot from "../../assets/reddot.svg";
1920
2021const Forum = ( ) => {
2122 const [ selectedTab , setSelectedTab ] = useState ( 1 ) ;
22- const router = useRouter ( ) ;
23+ const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
2324 const [ isRefreshing , setIsRefreshing ] = useState ( false ) ;
25+ const pageSize = 10 ;
26+ const router = useRouter ( ) ;
27+
28+ useEffect ( ( ) => {
29+ setCurrentPage ( 1 ) ;
30+ } , [ selectedTab ] ) ;
31+
32+ const { data : forumData , refetch : refetchForum } =
33+ api . discussion . getDiscussions . useQuery ( {
34+ page : currentPage ,
35+ pageSize,
36+ } ) ;
37+
38+ const { data : myPostsData , refetch : refetchMyPosts } =
39+ api . discussion . getDiscussionsByUser . useQuery ( {
40+ page : currentPage ,
41+ pageSize,
42+ } ) ;
2443
25- const { data : forumPosts , refetch : refetchForumPosts } =
26- api . discussion . getDiscussions . useQuery ( ) ;
27- const { data : myPosts , refetch : refetchMyPosts } =
28- api . discussion . getDiscussionsByUser . useQuery ( ) ;
2944 const { data : replies , refetch : refetchReplies } =
3045 api . discussion . getReplies . useQuery ( ) ;
31- const replyLength = replies ?. length ;
3246
33- const dataToDisplay =
34- selectedTab === 1 ? forumPosts : selectedTab === 2 ? myPosts : [ ] ;
47+ const currentData =
48+ selectedTab === 1 ? forumData : selectedTab === 2 ? myPostsData : null ;
49+
50+ const totalPages : number = currentData ?. totalPages ?? 0 ;
51+ const posts = currentData ?. posts ?? [ ] ;
52+
53+ const PaginationControls = ( ) => {
54+ if ( totalPages <= 1 ) return null ;
55+
56+ const getPageNumbers = ( ) => {
57+ const pages = [ ] ;
58+ const maxVisible = 5 ;
59+ let start = Math . max ( 1 , currentPage - 2 ) ;
60+ let end = Math . min ( totalPages , currentPage + 2 ) ;
61+
62+ if ( totalPages > maxVisible ) {
63+ if ( currentPage <= 3 ) {
64+ start = 1 ;
65+ end = maxVisible ;
66+ } else if ( currentPage >= totalPages - 2 ) {
67+ start = totalPages - maxVisible + 1 ;
68+ end = totalPages ;
69+ }
70+ }
3571
36- const onRefresh = async ( ) => {
72+ if ( start > 1 ) pages . push ( 1 , "..." ) ;
73+ for ( let i = start ; i <= end ; i ++ ) pages . push ( i ) ;
74+ if ( end < totalPages ) pages . push ( "..." , totalPages ) ;
75+
76+ return pages ;
77+ } ;
78+
79+ return (
80+ < View className = "my-4 flex-row items-center justify-center" >
81+ < TouchableOpacity
82+ onPress = { ( ) => setCurrentPage ( Math . max ( 1 , currentPage - 1 ) ) }
83+ disabled = { currentPage === 1 }
84+ >
85+ < MaterialIcons
86+ name = "chevron-left"
87+ size = { 24 }
88+ color = { currentPage === 1 ? "#ccc" : "#000" }
89+ />
90+ </ TouchableOpacity >
91+
92+ { getPageNumbers ( ) . map ( ( page , index ) =>
93+ page === "..." ? (
94+ < Text key = { `ellipsis-${ index } ` } className = "mx-2" >
95+ ...
96+ </ Text >
97+ ) : (
98+ < TouchableOpacity
99+ key = { page }
100+ className = { `mx-1 h-8 w-8 items-center justify-center rounded-full
101+ ${ currentPage === page ? "bg-blue-500" : "bg-gray-200" } ` }
102+ onPress = { ( ) => setCurrentPage ( Number ( page ) ) }
103+ >
104+ < Text
105+ className = { `${ currentPage === page ? "text-white" : "text-gray-700" } ` }
106+ >
107+ { page }
108+ </ Text >
109+ </ TouchableOpacity >
110+ ) ,
111+ ) }
112+
113+ < TouchableOpacity
114+ onPress = { ( ) => setCurrentPage ( Math . min ( totalPages , currentPage + 1 ) ) }
115+ disabled = { currentPage === totalPages }
116+ >
117+ < MaterialIcons
118+ name = "chevron-right"
119+ size = { 24 }
120+ color = { currentPage === totalPages ? "#ccc" : "#000" }
121+ />
122+ </ TouchableOpacity >
123+ </ View >
124+ ) ;
125+ } ;
126+
127+ const handleRefresh = async ( ) => {
37128 setIsRefreshing ( true ) ;
38129 try {
39- await Promise . all ( [
40- refetchForumPosts ( ) ,
41- refetchMyPosts ( ) ,
42- refetchReplies ( ) ,
43- ] ) ;
130+ await Promise . all ( [ refetchForum ( ) , refetchMyPosts ( ) , refetchReplies ( ) ] ) ;
44131 } catch ( error ) {
45- console . error ( "Failed to refresh forum :" , error ) ;
46- alert ( "Error refreshing forum . Please try again." ) ;
132+ console . error ( "Refresh failed :" , error ) ;
133+ alert ( "Refresh failed . Please try again." ) ;
47134 } finally {
48135 setIsRefreshing ( false ) ;
49136 }
@@ -56,28 +143,12 @@ const Forum = () => {
56143 </ View >
57144 < View className = "ml-4 mr-4 mt-4 flex-1 items-center justify-center" >
58145 < TabNav currentTab = { selectedTab } >
59- < TabNav . Tab
60- onPress = { ( ) => {
61- setSelectedTab ( 1 ) ;
62- } }
63- >
64- Feed
65- </ TabNav . Tab >
66- < TabNav . Tab
67- onPress = { ( ) => {
68- setSelectedTab ( 2 ) ;
69- } }
70- >
71- My Posts
72- </ TabNav . Tab >
73- < TabNav . Tab
74- onPress = { ( ) => {
75- setSelectedTab ( 3 ) ;
76- } }
77- >
146+ < TabNav . Tab onPress = { ( ) => setSelectedTab ( 1 ) } > Feed</ TabNav . Tab >
147+ < TabNav . Tab onPress = { ( ) => setSelectedTab ( 2 ) } > My Posts</ TabNav . Tab >
148+ < TabNav . Tab onPress = { ( ) => setSelectedTab ( 3 ) } >
78149 < View className = "relative" >
79- < Bell width = { 20 } height = { 20 } > </ Bell >
80- < View className = "absolute left-3.5 top-0 " >
150+ < Bell width = { 20 } height = { 20 } / >
151+ < View className = "absolute left-3.5 top-0" >
81152 < RedDot width = { 6 } height = { 6 } />
82153 </ View >
83154 </ View >
@@ -97,37 +168,31 @@ const Forum = () => {
97168 ListHeaderComponent = { renderHeader }
98169 data = { replies }
99170 keyExtractor = { ( item ) => item . id . toString ( ) }
100- renderItem = { ( { item, index } ) => {
101- if ( index == 0 ) {
102- return (
103- < View className = "bg-p-90 ml-3 mr-3 mt-2 rounded-tl-md rounded-tr-md p-4" >
104- < Text className = "font-headline-md pb-3" >
105- New Notifications
106- </ Text >
107- < ReplyNotification comment = { item } > </ ReplyNotification >
108- </ View >
109- ) ;
110- } else if ( index == replyLength ! - 1 ) {
111- return (
112- < View className = "bg-p-90 ml-3 mr-3 rounded-bl-lg rounded-br-lg p-4" >
113- < ReplyNotification comment = { item } > </ ReplyNotification >
114- </ View >
115- ) ;
116- } else {
117- return (
118- < View className = "bg-p-90 ml-3 mr-3 p-4" >
119- < ReplyNotification comment = { item } > </ ReplyNotification >
120- </ View >
121- ) ;
122- }
123- } }
171+ renderItem = { ( { item, index } ) => (
172+ < View
173+ className = { `bg-p-90 ml-3 mr-3 p-4 ${
174+ index === 0
175+ ? "mt-2 rounded-tl-md rounded-tr-md"
176+ : index === ( replies ?. length ?? 0 ) - 1
177+ ? "rounded-bl-lg rounded-br-lg"
178+ : ""
179+ } `}
180+ >
181+ { index === 0 && (
182+ < Text className = "font-headline-md pb-3" >
183+ New Notifications
184+ </ Text >
185+ ) }
186+ < ReplyNotification comment = { item } />
187+ </ View >
188+ ) }
124189 />
125190 </ View >
126191 ) : (
127192 < View className = "h-vh mb-16" >
128193 < FlatList
129194 ListHeaderComponent = { renderHeader }
130- data = { dataToDisplay }
195+ data = { posts }
131196 keyExtractor = { ( item ) => item . id . toString ( ) }
132197 renderItem = { ( { item } ) => (
133198 < View className = "mt-2" >
@@ -137,24 +202,23 @@ const Forum = () => {
137202 refreshControl = {
138203 < RefreshControl
139204 refreshing = { isRefreshing }
140- onRefresh = { onRefresh }
205+ onRefresh = { handleRefresh }
141206 />
142207 }
208+ ListFooterComponent = { < PaginationControls /> }
143209 />
144210 </ View >
145211 ) }
146212
147- { /* Floating Button */ }
148213 < TouchableOpacity
149- style = { {
150- position : "absolute" ,
151- bottom : 100 ,
152- right : 20 ,
153- } }
214+ style = { { position : "absolute" , bottom : 100 , right : 20 } }
215+ onPress = { ( ) => router . push ( "/createpost" ) }
154216 >
155217 < FloatingButton
156- onPress = { ( ) => router . push ( "/createpost" ) }
157218 icon = { true }
219+ onPress = { function ( ) : void {
220+ throw new Error ( "Function not implemented." ) ;
221+ } }
158222 />
159223 </ TouchableOpacity >
160224 </ View >
0 commit comments