Allow comment/post upvoting from other pages.

- Fixes #355
- Votes now coming back for posts and comments on search page.
This commit is contained in:
Dessalines 2020-01-20 18:39:45 -05:00
parent 86871d17ac
commit a964b4ce21
6 changed files with 154 additions and 99 deletions

View file

@ -19,6 +19,7 @@ pub struct Search {
sort: String,
page: Option<i64>,
limit: Option<i64>,
auth: Option<String>,
}
#[derive(Serialize, Deserialize)]
@ -313,6 +314,17 @@ impl Perform<SearchResponse> for Oper<Search> {
fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> {
let data: &Search = &self.data;
let user_id: Option<i32> = match &data.auth {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None,
},
None => None,
};
let sort = SortType::from_str(&data.sort)?;
let type_ = SearchType::from_str(&data.type_)?;
@ -330,6 +342,7 @@ impl Perform<SearchResponse> for Oper<Search> {
.show_nsfw(true)
.for_community_id(data.community_id)
.search_term(data.q.to_owned())
.my_user_id(user_id)
.page(data.page)
.limit(data.limit)
.list()?;
@ -338,6 +351,7 @@ impl Perform<SearchResponse> for Oper<Search> {
comments = CommentQueryBuilder::create(&conn)
.sort(&sort)
.search_term(data.q.to_owned())
.my_user_id(user_id)
.page(data.page)
.limit(data.limit)
.list()?;
@ -364,6 +378,7 @@ impl Perform<SearchResponse> for Oper<Search> {
.show_nsfw(true)
.for_community_id(data.community_id)
.search_term(data.q.to_owned())
.my_user_id(user_id)
.page(data.page)
.limit(data.limit)
.list()?;
@ -371,6 +386,7 @@ impl Perform<SearchResponse> for Oper<Search> {
comments = CommentQueryBuilder::create(&conn)
.sort(&sort)
.search_term(data.q.to_owned())
.my_user_id(user_id)
.page(data.page)
.limit(data.limit)
.list()?;

View file

@ -52,7 +52,6 @@ interface PostListingProps {
post: Post;
showCommunity?: boolean;
showBody?: boolean;
viewOnly?: boolean;
moderators?: Array<CommunityUser>;
admins?: Array<UserView>;
}
@ -118,10 +117,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
let post = this.props.post;
return (
<div class="listing col-12">
<div
className={`vote-bar mr-2 float-left small text-center ${this.props
.viewOnly && 'no-click'}`}
>
<div className={`vote-bar mr-2 float-left small text-center`}>
<button
disabled={!UserService.Instance.user}
className={`btn p-0 ${

View file

@ -12,6 +12,8 @@ import {
SearchForm,
SearchResponse,
SearchType,
CreatePostLikeResponse,
CommentResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
import {
@ -123,22 +125,18 @@ export class Search extends Component<any, SearchState> {
render() {
return (
<div class="container">
<div class="row">
<div class="col-12">
<h5>
<T i18nKey="search">#</T>
</h5>
{this.selects()}
{this.searchForm()}
{this.state.type_ == SearchType.All && this.all()}
{this.state.type_ == SearchType.Comments && this.comments()}
{this.state.type_ == SearchType.Posts && this.posts()}
{this.state.type_ == SearchType.Communities && this.communities()}
{this.state.type_ == SearchType.Users && this.users()}
{this.noResults()}
{this.paginator()}
</div>
</div>
<h5>
<T i18nKey="search">#</T>
</h5>
{this.selects()}
{this.searchForm()}
{this.state.type_ == SearchType.All && this.all()}
{this.state.type_ == SearchType.Comments && this.comments()}
{this.state.type_ == SearchType.Posts && this.posts()}
{this.state.type_ == SearchType.Communities && this.communities()}
{this.state.type_ == SearchType.Users && this.users()}
{this.noResults()}
{this.paginator()}
</div>
);
}
@ -252,54 +250,56 @@ export class Search extends Component<any, SearchState> {
return (
<div>
{combined.map(i => (
<div>
{i.type_ == 'posts' && (
<PostListing post={i.data as Post} showCommunity viewOnly />
)}
{i.type_ == 'comments' && (
<CommentNodes
nodes={[{ comment: i.data as Comment }]}
locked
noIndent
/>
)}
{i.type_ == 'communities' && (
<div>
<span>
<Link to={`/c/${(i.data as Community).name}`}>{`/c/${
(i.data as Community).name
}`}</Link>
</span>
<span>{` - ${(i.data as Community).title} - ${
(i.data as Community).number_of_subscribers
} subscribers`}</span>
</div>
)}
{i.type_ == 'users' && (
<div>
<span>
<Link
className="text-info"
to={`/u/${(i.data as UserView).name}`}
>
{(i.data as UserView).avatar && showAvatars() && (
<img
height="32"
width="32"
src={pictshareAvatarThumbnail(
(i.data as UserView).avatar
)}
class="rounded-circle mr-1"
/>
)}
<span>{`/u/${(i.data as UserView).name}`}</span>
</Link>
</span>
<span>{` - ${
(i.data as UserView).comment_score
} comment karma`}</span>
</div>
)}
<div class="row">
<div class="col-12">
{i.type_ == 'posts' && (
<PostListing post={i.data as Post} showCommunity />
)}
{i.type_ == 'comments' && (
<CommentNodes
nodes={[{ comment: i.data as Comment }]}
locked
noIndent
/>
)}
{i.type_ == 'communities' && (
<div>
<span>
<Link to={`/c/${(i.data as Community).name}`}>{`/c/${
(i.data as Community).name
}`}</Link>
</span>
<span>{` - ${(i.data as Community).title} - ${
(i.data as Community).number_of_subscribers
} subscribers`}</span>
</div>
)}
{i.type_ == 'users' && (
<div>
<span>
<Link
className="text-info"
to={`/u/${(i.data as UserView).name}`}
>
{(i.data as UserView).avatar && showAvatars() && (
<img
height="32"
width="32"
src={pictshareAvatarThumbnail(
(i.data as UserView).avatar
)}
class="rounded-circle mr-1"
/>
)}
<span>{`/u/${(i.data as UserView).name}`}</span>
</Link>
</span>
<span>{` - ${
(i.data as UserView).comment_score
} comment karma`}</span>
</div>
)}
</div>
</div>
))}
</div>
@ -308,55 +308,69 @@ export class Search extends Component<any, SearchState> {
comments() {
return (
<div>
<>
{this.state.searchResponse.comments.map(comment => (
<CommentNodes nodes={[{ comment: comment }]} locked noIndent />
<div class="row">
<div class="col-12">
<CommentNodes nodes={[{ comment: comment }]} locked noIndent />
</div>
</div>
))}
</div>
</>
);
}
posts() {
return (
<div>
<>
{this.state.searchResponse.posts.map(post => (
<PostListing post={post} showCommunity viewOnly />
<div class="row">
<div class="col-12">
<PostListing post={post} showCommunity />
</div>
</div>
))}
</div>
</>
);
}
// Todo possibly create UserListing and CommunityListing
communities() {
return (
<div>
<>
{this.state.searchResponse.communities.map(community => (
<div>
<span>
<Link to={`/c/${community.name}`}>{`/c/${community.name}`}</Link>
</span>
<span>{` - ${community.title} - ${community.number_of_subscribers} subscribers`}</span>
<div class="row">
<div class="col-12">
<span>
<Link
to={`/c/${community.name}`}
>{`/c/${community.name}`}</Link>
</span>
<span>{` - ${community.title} - ${community.number_of_subscribers} subscribers`}</span>
</div>
</div>
))}
</div>
</>
);
}
users() {
return (
<div>
<>
{this.state.searchResponse.users.map(user => (
<div>
<span>
<Link
className="text-info"
to={`/u/${user.name}`}
>{`/u/${user.name}`}</Link>
</span>
<span>{` - ${user.comment_score} comment karma`}</span>
<div class="row">
<div class="col-12">
<span>
<Link
className="text-info"
to={`/u/${user.name}`}
>{`/u/${user.name}`}</Link>
</span>
<span>{` - ${user.comment_score} comment karma`}</span>
</div>
</div>
))}
</div>
</>
);
}
@ -477,6 +491,30 @@ export class Search extends Component<any, SearchState> {
}`;
window.scrollTo(0, 0);
this.setState(this.state);
} else if (op == UserOperation.CreateCommentLike) {
let res: CommentResponse = msg;
let found: Comment = this.state.searchResponse.comments.find(
c => c.id === res.comment.id
);
found.score = res.comment.score;
found.upvotes = res.comment.upvotes;
found.downvotes = res.comment.downvotes;
if (res.comment.my_vote !== null) {
found.my_vote = res.comment.my_vote;
found.upvoteLoading = false;
found.downvoteLoading = false;
}
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
let res: CreatePostLikeResponse = msg;
let found = this.state.searchResponse.posts.find(
c => c.id == res.post.id
);
found.my_vote = res.post.my_vote;
found.score = res.post.score;
found.upvotes = res.post.upvotes;
found.downvotes = res.post.downvotes;
this.setState(this.state);
}
}
}

View file

@ -18,6 +18,7 @@ import {
BanUserResponse,
AddAdminResponse,
DeleteAccountForm,
CreatePostLikeResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import {
@ -307,7 +308,6 @@ export class User extends Component<any, UserState> {
post={i.data as Post}
admins={this.state.admins}
showCommunity
viewOnly
/>
) : (
<CommentNodes
@ -340,12 +340,7 @@ export class User extends Component<any, UserState> {
return (
<div>
{this.state.posts.map(post => (
<PostListing
post={post}
admins={this.state.admins}
showCommunity
viewOnly
/>
<PostListing post={post} admins={this.state.admins} showCommunity />
))}
</div>
);
@ -1043,6 +1038,14 @@ export class User extends Component<any, UserState> {
found.downvotes = res.comment.downvotes;
if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote;
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
let res: CreatePostLikeResponse = msg;
let found = this.state.posts.find(c => c.id == res.post.id);
found.my_vote = res.post.my_vote;
found.score = res.post.score;
found.upvotes = res.post.upvotes;
found.downvotes = res.post.downvotes;
this.setState(this.state);
} else if (op == UserOperation.BanUser) {
let res: BanUserResponse = msg;
this.state.comments

View file

@ -700,6 +700,7 @@ export interface SearchForm {
sort: string;
page?: number;
limit?: number;
auth?: string;
}
export interface SearchResponse {

View file

@ -255,6 +255,7 @@ export class WebSocketService {
}
public search(form: SearchForm) {
this.setAuth(form, false);
this.subject.next(this.wsSendWrapper(UserOperation.Search, form));
}