Skip to content

Commit d606cab

Browse files
Implemented posts by tag and search features.
1 parent eadc14e commit d606cab

File tree

8 files changed

+99
-32
lines changed

8 files changed

+99
-32
lines changed

src/App.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ const App = () => (
1515
<Route path="/login" component={Login}/>
1616
<Route path="/registration" component={Registration}/>
1717
<Route path="/posts/new" component={NewPost}/>
18-
<Route path="/posts/page/:page" render={(props) => (
19-
<Posts key={props.location.search} {...props}/>)
20-
} />
18+
2119
<Route path="/posts" component={Posts} />
2220
<Redirect exact path="/" to="/posts"/>
2321
<Route path="*">

src/components/posts/Pagination.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
import React from "react";
2-
import {PostsModel} from "../../models/PostModels";
2+
import {PostsPaginationModel} from "../../models/PostModels";
33
import classNames from "classnames";
44
import {NavLink} from "react-router-dom";
55

6-
const Pagination: React.FC<PostsModel> = (posts) => {
6+
const Pagination: React.FC<PostsPaginationModel> = (postsPagination) => {
7+
let posts = postsPagination.posts
8+
let firstPageUrl = "/posts?page=1";
9+
let prevPageUrl = `/posts?page=${posts.pageNumber-1}`;
10+
let nextPageUrl = `/posts?page=${posts.pageNumber+1}`;
11+
let lastPageUrl = `/posts?page=${posts.totalPages}`;
12+
13+
if(postsPagination.tag) {
14+
firstPageUrl += `&tag=${postsPagination.tag}`;
15+
prevPageUrl += `&tag=${postsPagination.tag}`;
16+
nextPageUrl += `&tag=${postsPagination.tag}`;
17+
lastPageUrl += `&tag=${postsPagination.tag}`;
18+
}
19+
20+
if(postsPagination.query) {
21+
firstPageUrl += `&query=${postsPagination.query}`;
22+
prevPageUrl += `&query=${postsPagination.query}`;
23+
nextPageUrl += `&query=${postsPagination.query}`;
24+
lastPageUrl += `&query=${postsPagination.query}`;
25+
}
726

827
return (
928
<div>
@@ -14,25 +33,25 @@ const Pagination: React.FC<PostsModel> = (posts) => {
1433
"page-item": true,
1534
disabled: !posts.hasPrevious
1635
})}>
17-
<NavLink className="page-link" to="/posts">First</NavLink>
36+
<NavLink className="page-link" to={`${firstPageUrl}`}>First</NavLink>
1837
</li>
1938
<li className={classNames({
2039
"page-item": true,
2140
disabled: !posts.hasPrevious
2241
})}>
23-
<NavLink className="page-link" to={`/posts/page/${posts.pageNumber-1}`}>Previous</NavLink>
42+
<NavLink className="page-link" to={`${prevPageUrl}`}>Previous</NavLink>
2443
</li>
2544
<li className={classNames({
2645
"page-item": true,
2746
disabled: !posts.hasNext
2847
})}>
29-
<NavLink className="page-link" to={`/posts/page/${posts.pageNumber+1}`}>Next</NavLink>
48+
<NavLink className="page-link" to={`${nextPageUrl}`}>Next</NavLink>
3049
</li>
3150
<li className={classNames({
3251
"page-item": true,
3352
disabled: !posts.hasNext
3453
})}>
35-
<NavLink className="page-link" to={`/posts/page/${posts.totalPages}`}>Last</NavLink>
54+
<NavLink className="page-link" to={`${lastPageUrl}`}>Last</NavLink>
3655
</li>
3756
</ul>
3857
</nav>

src/components/posts/Post.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {PostModel} from "../../models/PostModels";
55
const Post: React.FC<PostModel> = (post) => {
66
const tags = post.tags.map(tag => {
77
return (<span key={tag} style={{"fontSize": "20px"}}>
8-
<NavLink className="badge badge-primary" to={`/tags/${tag}`}>
8+
<NavLink className="badge badge-primary" to={`/posts?tag=${tag}`}>
99
{tag}
1010
</NavLink>
1111
&nbsp;

src/components/posts/Search.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
import React from 'react';
1+
import React, {useState} from "react";
2+
3+
interface SearchProps {
4+
ClickHandler: (query: string) => void
5+
}
6+
7+
const Search : React.FC<SearchProps>= ( props ) => {
8+
const [query, setQuery] = useState("");
29

3-
const Search = () => {
410
return (
511
<div>
612
<form className="form-inline pb-3" method="get">
713
<div className="form-group col-md-11">
8-
<input className="col-md-12 form-control" type="search" name="query" placeholder="Search for"/>
14+
<input className="col-md-12 form-control" type="search" name="query" placeholder="Search for"
15+
value={query}
16+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}/>
917
</div>
10-
<button className="btn btn-primary btn" type="submit">Search</button>
18+
<button className="btn btn-primary btn" type="button" onClick={(e) => props.ClickHandler(query)}>Search</button>
1119
</form>
1220
</div>
1321
);

src/components/posts/TagNav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const TagNav :React.FC<TagList> = (tagList) => {
1616
<div className="list-group list-group-flush">
1717
{tagList.tags.map(tag => {
1818
return(
19-
<NavLink to={`/tags/${tag.name}`} key={tag.id}
19+
<NavLink to={`/posts?tag=${tag.name}`} key={tag.id}
2020
className="list-group-item list-group-item-action badge badge-primary"
2121
>
2222
<i className="fas fa-tag"/>&nbsp;

src/models/PostModels.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@ export interface PostsModel {
1616
isLast: boolean,
1717
hasNext: boolean,
1818
hasPrevious: boolean;
19+
}
20+
21+
export interface PostsPaginationModel {
22+
tag?: string
23+
query?: string
24+
page?: number
25+
posts: PostsModel
1926
}

src/pages/posts/Posts.tsx

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,34 @@ import React, {useState, useEffect} from "react";
33
import PostService from '../../services/PostService';
44
import PostList from "../../components/posts/PostList";
55
import TagNav from "../../components/posts/TagNav";
6-
import {PostsModel} from "../../models/PostModels";
6+
import {PostsModel, PostsPaginationModel} from "../../models/PostModels";
77
import Search from "../../components/posts/Search";
88
import Pagination from "../../components/posts/Pagination";
9-
import { useParams } from "react-router-dom";
9+
import { useHistory, RouteComponentProps} from "react-router-dom";
10+
11+
type PostsState = {
12+
tag?: string
13+
query?: string
14+
page?: number
15+
}
16+
17+
type PostsProps = RouteComponentProps<{}, {}, PostsState>;
18+
19+
const Posts : React.FC<PostsProps> = ( props ) => {
20+
const history = useHistory();
21+
const postService = new PostService();
22+
23+
const queryParams = new URLSearchParams(props.location.search);
24+
25+
let pageNo = queryParams.get('page') || "1";
26+
let page = +pageNo;
27+
let tag = queryParams.get('tag') || "";
28+
let query = queryParams.get('query') || "";
29+
30+
//console.log("page:", page)
31+
//console.log("query:", query)
32+
//console.log("tag:", tag)
1033

11-
const Posts = ( ) => {
12-
let { page } = useParams();
13-
if(!page) {
14-
page = 1;
15-
}
16-
//console.log("page", page)
17-
const postService = new PostService()
1834
const initialValue: PostsModel = {
1935
hasNext: false,
2036
hasPrevious: false,
@@ -26,7 +42,12 @@ const Posts = ( ) => {
2642
data: []}
2743
const [posts, setPosts] = useState(initialValue)
2844
const [tags, setTags] = useState([])
29-
45+
let postsPaginationModel : PostsPaginationModel = {
46+
page: page,
47+
tag: tag,
48+
query: query,
49+
posts: posts || {}
50+
}
3051
useEffect(() => {
3152
postService.fetchTags()
3253
.then(response => {
@@ -38,25 +59,28 @@ const Posts = ( ) => {
3859
}, []);
3960

4061
useEffect(() => {
41-
postService.fetchPosts(page)
62+
postService.fetchPosts(page, tag, query)
4263
.then(response => {
4364
setPosts({...response.data})
4465
})
4566
.catch(e => {
4667
alert('Failed to get posts')
4768
});
48-
}, [page]);
69+
}, [page, tag, query]);
4970

71+
const searchHandler = (query: string) => {
72+
history.push(`/posts?query=${query}`);
73+
}
5074
return (
5175
<div className="row">
5276
<div className="col-12">
5377
<div className="mt-3">
5478
<div className="row">
5579
<div className="offset-1 col-8">
56-
<Search />
57-
<Pagination {...posts} />
80+
<Search ClickHandler={searchHandler}/>
81+
<Pagination {...postsPaginationModel} />
5882
<PostList {...posts}/>
59-
<Pagination {...posts} />
83+
<Pagination {...postsPaginationModel} />
6084
</div>
6185
<div className="col-3">
6286
<TagNav tags={tags}/>

src/services/PostService.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,19 @@ export default class PostService {
66
return axios.get("/tags");
77
}
88

9-
fetchPosts = (page: number) => {
10-
return axios.get(`/links?page=${page}`);
9+
fetchPosts = (page: number, tag: string, query: string) => {
10+
let url = `/links?page=${page}`;
11+
if(tag) {
12+
url += `&tag=${tag}`;
13+
}
14+
if(query) {
15+
url += `&query=${query}`;
16+
}
17+
return axios.get(url);
18+
}
19+
20+
fetchPostsByTag = (tag:string, page: number) => {
21+
return axios.get(`/links?tag=${tag}&page=${page}`);
1122
}
1223

1324
createPost = (post: PostModel) => {

0 commit comments

Comments
 (0)