Skip to content

Commit caf68d5

Browse files
committed
Add Pagination to all feeds
1 parent d11fa1f commit caf68d5

File tree

16 files changed

+670
-105
lines changed

16 files changed

+670
-105
lines changed

frontend/package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"moment-timezone": "^0.5.33",
3535
"prop-types": "^15.7.2",
3636
"react-flip-move": "^3.0.4",
37+
"react-paginate": "^7.1.3",
3738
"react-router": "^6.0.0-beta.0",
3839
"react-router-dom": "^6.0.0-beta.0",
3940
"react-swipeable-views": "^0.14.0",

frontend/src/components/Feed.js

+46-8
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,52 @@ import '../styles/components/Feed.css';
1010

1111
function Feed({ user }) {
1212
const [posts, setPosts] = useState([]);
13+
const [pageCount, setPageCount] = useState(1);
14+
const [currentPage, setCurrentPage] = useState(0);
1315

14-
const fetchPosts = () => {
15-
return APIHelper.getAllTweets({ sort: 'latest', related: 'likes_current' })
16-
.then(data => {
17-
if (APIHelper.type(data) === "Object" && data.error) {
18-
return console.error(data.error);
16+
const [following_posts, setFollowingPosts] = useState([]);
17+
const [followingPageCount, setFollowingPageCount] = useState(1);
18+
const [currentFollowingPage, setCurrentFollowingPage] = useState(0);
19+
20+
const fetchPosts = (is_following = false) => {
21+
const args = {
22+
sort: 'latest',
23+
related: 'likes_current',
24+
page: (is_following ? currentFollowingPage : currentPage) + 1,
25+
}
26+
if (is_following) {
27+
args.filter = 'following';
28+
}
29+
return APIHelper.getAllTweets(args)
30+
.then(obj => {
31+
if (!('tweets' in obj)) {
32+
return console.error('tweets not in getAllTweets')
1933
}
20-
setPosts(data);
34+
if (!('pages' in obj)) {
35+
return console.error('pages not in getAllTweets')
36+
}
37+
is_following ? setFollowingPageCount(obj.pages) : setPageCount(obj.pages);
38+
return obj.tweets.then(data => {
39+
if (APIHelper.type(data) === "Object" && data.error) {
40+
return console.error(data.error);
41+
}
42+
is_following? setFollowingPosts(data) : setPosts(data);
43+
});
2144
});
2245
};
2346

2447
useEffect(() => {
2548
fetchPosts(); // fetch immediately
26-
}, []);
49+
}, [currentPage]);
50+
useEffect(() => {
51+
fetchPosts(true); // fetch immediately
52+
}, [currentFollowingPage]);
2753

2854
const handleScroll = (e) => {
2955
const top = e.target.scrollTop === 0;
3056
if (top) {
3157
fetchPosts(); // only fetch when scroll to the top of feeds
58+
fetchPosts(true);
3259
}
3360
};
3461

@@ -45,7 +72,18 @@ function Feed({ user }) {
4572
<div className="feed__seperator"></div>
4673

4774
{/* FeedTweets Tabs */}
48-
<FeedTweets user={user} tweets={posts} fetchPosts={fetchPosts} />
75+
<FeedTweets
76+
user={user}
77+
tweets={posts}
78+
tweetsFollowing={following_posts}
79+
fetchPosts={fetchPosts}
80+
pageCount={pageCount}
81+
currentPage={currentPage}
82+
setCurrentPage={setCurrentPage}
83+
followingPageCount={followingPageCount}
84+
currentFollowingPage={currentFollowingPage}
85+
setCurrentFollowingPage={setCurrentFollowingPage}
86+
/>
4987
</div>
5088
);
5189
};

frontend/src/components/FeedTweets.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Box from '@material-ui/core/Box';
1313
// Custom Components
1414
import Post from './Post';
1515
import HeadingCard from './HeadingCard';
16+
import TweetPagination from './TweetPagination';
1617
// Custom Styling
1718
import '../styles/components/FeedTweets.css'
1819

@@ -108,11 +109,14 @@ const AntTab = withStyles((theme) => ({
108109
selected: {},
109110
}))((props) => <Tab className="feedTweets__tab" {...props} />);
110111

111-
export default function FeedTweets({ user, tweets, fetchPosts }) {
112+
export default function FeedTweets({
113+
user, tweets, tweetsFollowing, fetchPosts,
114+
pageCount, currentPage, setCurrentPage,
115+
followingPageCount, currentFollowingPage, setCurrentFollowingPage
116+
}) {
112117
const classes = useStyles();
113118
const theme = useTheme();
114119
const [value, setValue] = useState(0);
115-
const tweetsFollowing = tweets.filter(post => post.is_following);
116120

117121
const handleChange = (event, newValue) => {
118122
setValue(newValue);
@@ -163,6 +167,12 @@ export default function FeedTweets({ user, tweets, fetchPosts }) {
163167
<HeadingCard line_1={`Nobody has Tweeted anything yet`} line_2="When they do, their tweets will show up here."/>
164168
: null
165169
}
170+
{/* Pagination */}
171+
<TweetPagination
172+
pageCount={pageCount}
173+
currentPage={currentPage}
174+
setCurrentPage={setCurrentPage}
175+
/>
166176
</TabPanel>
167177
<TabPanel className="feedTweets__tweetsTabPanel" value={value} index={1} dir={theme.direction}>
168178
{/* Tweets by users following */}
@@ -190,6 +200,12 @@ export default function FeedTweets({ user, tweets, fetchPosts }) {
190200
<HeadingCard line_1={`Users you follow haven't Tweeted anything yet`} line_2="When they do, their tweets will show up here."/>
191201
: null
192202
}
203+
{/* Pagination */}
204+
<TweetPagination
205+
pageCount={followingPageCount}
206+
currentPage={currentFollowingPage}
207+
setCurrentPage={setCurrentFollowingPage}
208+
/>
193209
</TabPanel>
194210
</SwipeableViews>
195211
</div>

frontend/src/components/LikeButton.js

+2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ function LikeButton({tweet, liked, fetchPosts}) {
1515
return console.error(data.error);
1616
}
1717
fetchPosts();
18+
fetchPosts(true);
1819
});
1920
} else {
2021
APIHelper.unlikeTweet(tweet).then(data => {
2122
if (APIHelper.type(data) === "Object" && data.error) {
2223
return console.error(data.error);
2324
}
2425
fetchPosts();
26+
fetchPosts(true);
2527
});
2628
}
2729
};

frontend/src/components/MoreButton.js

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ function MoreButton({ tweetUserID, avatar, text, image, tweet, fetchPosts, curre
8282
return console.error(data.error);
8383
}
8484
fetchPosts();
85+
fetchPosts(true);
8586
});
8687
};
8788

frontend/src/components/Profile.js

+33-12
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ function Profile({ user, classes }) {
4242
const [unfollowModalOpen, setUnfollowModalOpen] = useState(false);
4343
const [isFollowing, setIsFollowing] = useState(false);
4444

45+
/** Pagination */
46+
const [tweets_currentPage, tweets_setCurrentPage] = useState(0);
47+
const [media_currentPage, media_setCurrentPage] = useState(0);
48+
const [likes_currentPage, likes_setCurrentPage] = useState(0);
49+
useEffect(() => {
50+
loadUserProfile();
51+
}, [tweets_currentPage, media_currentPage, likes_currentPage]);
52+
4553
const loadUserFollowed = (userId) => {
4654
APIHelper.isUserFollowedByMe(userId)
4755
.then(data => {
@@ -53,17 +61,20 @@ function Profile({ user, classes }) {
5361
};
5462

5563
const loadUserProfile = () => {
56-
APIHelper.getUserInfoByUsername(username)
57-
.then(data => {
58-
if (APIHelper.type(data) === "Object" && data.error) {
59-
console.error(data.error);
60-
}
61-
setProfileUser(data);
62-
if (profileUser.birth_date) {
63-
setEditBirthDate(moment(profileUser.birth_date));
64-
}
65-
loadUserFollowed(profileUser.id);
66-
});
64+
APIHelper.getUserInfoByUsername(username, {
65+
tweets_page: tweets_currentPage + 1,
66+
media_page: media_currentPage + 1,
67+
likes_page: likes_currentPage + 1
68+
}).then(data => {
69+
if (APIHelper.type(data) === "Object" && data.error) {
70+
console.error(data.error);
71+
}
72+
setProfileUser(data);
73+
if (profileUser.birth_date) {
74+
setEditBirthDate(moment(profileUser.birth_date));
75+
}
76+
loadUserFollowed(profileUser.id);
77+
});
6778
};
6879

6980
const handleScroll = (e) => {
@@ -214,7 +225,17 @@ function Profile({ user, classes }) {
214225
<span className="profile__info__followersCount"><b>{profileUser.followers_count}</b> Followers</span>
215226
</p>
216227
</div>
217-
<ProfileTweets currentUser={user} profileUser={profileUser} loadUserProfile={loadUserProfile}/>
228+
<ProfileTweets
229+
currentUser={user}
230+
profileUser={profileUser}
231+
loadUserProfile={loadUserProfile}
232+
tweets_currentPage={tweets_currentPage}
233+
tweets_setCurrentPage={tweets_setCurrentPage}
234+
media_currentPage={media_currentPage}
235+
media_setCurrentPage={media_setCurrentPage}
236+
likes_currentPage={likes_currentPage}
237+
likes_setCurrentPage={likes_setCurrentPage}
238+
/>
218239

219240
{/** Unfollow Dialog */}
220241
<Dialog

frontend/src/components/ProfileTweets.js

+28-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Box from '@material-ui/core/Box';
1414
// Custom Components
1515
import Post from './Post';
1616
import HeadingCard from './HeadingCard';
17+
import TweetPagination from './TweetPagination';
1718
// Custom Styling
1819
import '../styles/components/ProfileTweets.css'
1920

@@ -111,7 +112,12 @@ const AntTab = withStyles((theme) => ({
111112
selected: {},
112113
}))((props) => <NavLink className="profileTweets__tab__link" to={props.to}><Tab className="profileTweets__tab" {...props} /></NavLink>);
113114

114-
export default function ProfileTweets({ currentUser, profileUser, loadUserProfile }) {
115+
export default function ProfileTweets({
116+
currentUser, profileUser, loadUserProfile,
117+
tweets_currentPage, tweets_setCurrentPage,
118+
media_currentPage, media_setCurrentPage,
119+
likes_currentPage, likes_setCurrentPage,
120+
}) {
115121
const classes = useStyles();
116122
const theme = useTheme();
117123
const [value, setValue] = useState(0);
@@ -125,7 +131,7 @@ export default function ProfileTweets({ currentUser, profileUser, loadUserProfil
125131
} else {
126132
setValue(0)
127133
}
128-
})
134+
});
129135

130136
const handleChange = (event, newValue) => {
131137
setValue(newValue);
@@ -177,11 +183,17 @@ export default function ProfileTweets({ currentUser, profileUser, loadUserProfil
177183
<HeadingCard line_1={`@${profileUser.username} hasn't Tweeted anything yet`} line_2="When they do, their tweets will show up here."/>
178184
: null
179185
}
186+
{/* Pagination */}
187+
<TweetPagination
188+
pageCount={profileUser.tweets_pages}
189+
currentPage={tweets_currentPage}
190+
setCurrentPage={tweets_setCurrentPage}
191+
/>
180192
</TabPanel>
181193
<TabPanel className="profileTweets__tweetsTabPanel" value={value} index={1} dir={theme.direction}>
182194
{/* User's Tweets with Media */}
183195
<FlipMove>
184-
{profileUser.tweets.filter(post => post.image).map(post => (
196+
{profileUser.media.map(post => (
185197
<Post
186198
key={post.id}
187199
tweet={post.id}
@@ -200,10 +212,16 @@ export default function ProfileTweets({ currentUser, profileUser, loadUserProfil
200212
/>
201213
))}
202214
</FlipMove>
203-
{profileUser.tweets.filter(post => post.image).length === 0 ?
215+
{profileUser.media.length === 0 ?
204216
<HeadingCard line_1={`@${profileUser.username} hasn't Tweeted any photos`} line_2="When they do, their media will show up here."/>
205217
: null
206218
}
219+
{/* Pagination */}
220+
<TweetPagination
221+
pageCount={profileUser.media_pages}
222+
currentPage={media_currentPage}
223+
setCurrentPage={media_setCurrentPage}
224+
/>
207225
</TabPanel>
208226
<TabPanel className="profileTweets__tweetsTabPanel" value={value} index={2} dir={theme.direction}>
209227
{/* User's LikedTweets */}
@@ -233,6 +251,12 @@ export default function ProfileTweets({ currentUser, profileUser, loadUserProfil
233251
<HeadingCard line_1={`@${profileUser.username} hasn't Liked any Tweets`} line_2="When they do, their liked tweets will show up here."/>
234252
: null
235253
}
254+
{/* Pagination */}
255+
<TweetPagination
256+
pageCount={profileUser.likes_pages}
257+
currentPage={likes_currentPage}
258+
setCurrentPage={likes_setCurrentPage}
259+
/>
236260
</TabPanel>
237261
</SwipeableViews>
238262
</div>
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// React Imports
2+
import React from 'react';
3+
// Components Imports
4+
import ReactPaginate from 'react-paginate';
5+
// Custom Styling
6+
import '../styles/components/TweetPagination.css';
7+
8+
function TweetPagination({ pageCount, currentPage, setCurrentPage }) {
9+
return (
10+
<div className="tweetPagination disable-select">
11+
<ReactPaginate
12+
initialPage={currentPage}
13+
forcePage={currentPage}
14+
pageCount={pageCount}
15+
marginPagesDisplayed={2}
16+
pageRangeDisplayed={5}
17+
onPageChange={(e) => setCurrentPage(e.selected)}
18+
disableInitialCallback = {true}
19+
nextLabel="&rarr;"
20+
previousLabel="&larr;"
21+
breakLabel={"..."}
22+
breakClassName={"break"}
23+
activeClassName={"active"}
24+
/>
25+
</div>
26+
);
27+
}
28+
29+
export default TweetPagination;

frontend/src/components/Tweetbox.js

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ function Tweetbox({ isEditMode, avatar, fetchPosts, initText='', initImage='', t
2929
}
3030
if (handleEditModalClose) handleEditModalClose();
3131
fetchPosts();
32+
fetchPosts(true);
3233
});
3334
}
3435
} else {
@@ -43,6 +44,7 @@ function Tweetbox({ isEditMode, avatar, fetchPosts, initText='', initImage='', t
4344
setTweetMessage('');
4445
setTweetImage('');
4546
fetchPosts();
47+
fetchPosts(true);
4648
});
4749
}
4850
};

0 commit comments

Comments
 (0)