mirror of
https://github.com/astuto/astuto.git
synced 2025-12-16 11:47:56 +01:00
Add Likes in Post component
This commit is contained in:
@@ -1,11 +1,28 @@
|
|||||||
class LikesController < ApplicationController
|
class LikesController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!, only: [:create, :destroy]
|
||||||
|
|
||||||
|
def index
|
||||||
|
likes = Like
|
||||||
|
.select(
|
||||||
|
:id,
|
||||||
|
:full_name,
|
||||||
|
:email
|
||||||
|
)
|
||||||
|
.left_outer_joins(:user)
|
||||||
|
.where(post_id: params[:post_id])
|
||||||
|
|
||||||
|
render json: likes
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
like = Like.new(like_params)
|
like = Like.new(like_params)
|
||||||
|
|
||||||
if like.save
|
if like.save
|
||||||
render json: like, status: :created
|
render json: {
|
||||||
|
id: like.id,
|
||||||
|
full_name: current_user.full_name,
|
||||||
|
email: current_user.email,
|
||||||
|
}, status: :created
|
||||||
else
|
else
|
||||||
render json: {
|
render json: {
|
||||||
error: I18n.t('errors.likes.create', message: like.errors.full_messages)
|
error: I18n.t('errors.likes.create', message: like.errors.full_messages)
|
||||||
@@ -15,11 +32,14 @@ class LikesController < ApplicationController
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
like = Like.find_by(like_params)
|
like = Like.find_by(like_params)
|
||||||
|
id = like.id
|
||||||
|
|
||||||
return if like.nil?
|
return if like.nil?
|
||||||
|
|
||||||
if like.destroy
|
if like.destroy
|
||||||
render json: {}, status: :accepted
|
render json: {
|
||||||
|
id: id,
|
||||||
|
}, status: :accepted
|
||||||
else
|
else
|
||||||
render json: {
|
render json: {
|
||||||
error: I18n.t('errors.likes.destroy', message: like.errors.full_messages)
|
error: I18n.t('errors.likes.destroy', message: like.errors.full_messages)
|
||||||
|
|||||||
59
app/javascript/actions/requestLikes.ts
Normal file
59
app/javascript/actions/requestLikes.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Action } from 'redux';
|
||||||
|
import { ThunkAction } from 'redux-thunk';
|
||||||
|
|
||||||
|
import ILikeJSON from '../interfaces/json/ILike';
|
||||||
|
|
||||||
|
import { State } from '../reducers/rootReducer';
|
||||||
|
|
||||||
|
export const LIKES_REQUEST_START = 'LIKES_REQUEST_START';
|
||||||
|
interface LikesRequestStartAction {
|
||||||
|
type: typeof LIKES_REQUEST_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LIKES_REQUEST_SUCCESS = 'LIKES_REQUEST_SUCCESS';
|
||||||
|
interface LikesRequestSuccessAction {
|
||||||
|
type: typeof LIKES_REQUEST_SUCCESS;
|
||||||
|
likes: Array<ILikeJSON>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LIKES_REQUEST_FAILURE = 'LIKES_REQUEST_FAILURE';
|
||||||
|
interface LikesRequestFailureAction {
|
||||||
|
type: typeof LIKES_REQUEST_FAILURE;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LikesRequestActionTypes =
|
||||||
|
LikesRequestStartAction |
|
||||||
|
LikesRequestSuccessAction |
|
||||||
|
LikesRequestFailureAction;
|
||||||
|
|
||||||
|
|
||||||
|
const likesRequestStart = (): LikesRequestActionTypes => ({
|
||||||
|
type: LIKES_REQUEST_START,
|
||||||
|
});
|
||||||
|
|
||||||
|
const likesRequestSuccess = (
|
||||||
|
likes: Array<ILikeJSON>,
|
||||||
|
): LikesRequestActionTypes => ({
|
||||||
|
type: LIKES_REQUEST_SUCCESS,
|
||||||
|
likes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const likesRequestFailure = (error: string): LikesRequestActionTypes => ({
|
||||||
|
type: LIKES_REQUEST_FAILURE,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const requestLikes = (
|
||||||
|
postId: number,
|
||||||
|
): ThunkAction<void, State, null, Action<string>> => async (dispatch) => {
|
||||||
|
dispatch(likesRequestStart());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/posts/${postId}/likes`);
|
||||||
|
const json = await response.json();
|
||||||
|
dispatch(likesRequestSuccess(json));
|
||||||
|
} catch (e) {
|
||||||
|
dispatch(likesRequestFailure(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,27 @@ import { Action } from "redux";
|
|||||||
import { ThunkAction } from "redux-thunk";
|
import { ThunkAction } from "redux-thunk";
|
||||||
|
|
||||||
import { State } from "../reducers/rootReducer";
|
import { State } from "../reducers/rootReducer";
|
||||||
|
import ILikeJSON from "../interfaces/json/ILike";
|
||||||
|
|
||||||
export const LIKE_SUBMIT_SUCCESS = 'LIKE_SUBMIT_SUCCESS';
|
export const LIKE_SUBMIT_SUCCESS = 'LIKE_SUBMIT_SUCCESS';
|
||||||
interface LikeSubmitSuccessAction {
|
interface LikeSubmitSuccessAction {
|
||||||
type: typeof LIKE_SUBMIT_SUCCESS,
|
type: typeof LIKE_SUBMIT_SUCCESS,
|
||||||
postId: number;
|
postId: number;
|
||||||
isLike: boolean;
|
isLike: boolean;
|
||||||
|
like: ILikeJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LikeActionTypes = LikeSubmitSuccessAction;
|
export type LikeActionTypes = LikeSubmitSuccessAction;
|
||||||
|
|
||||||
const likeSubmitSuccess = (postId: number, isLike: boolean): LikeSubmitSuccessAction => ({
|
const likeSubmitSuccess = (
|
||||||
|
postId: number,
|
||||||
|
isLike: boolean,
|
||||||
|
like: ILikeJSON,
|
||||||
|
): LikeSubmitSuccessAction => ({
|
||||||
type: LIKE_SUBMIT_SUCCESS,
|
type: LIKE_SUBMIT_SUCCESS,
|
||||||
postId,
|
postId,
|
||||||
isLike,
|
isLike,
|
||||||
|
like,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const submitLike = (
|
export const submitLike = (
|
||||||
@@ -32,9 +39,10 @@ export const submitLike = (
|
|||||||
'X-CSRF-Token': authenticityToken,
|
'X-CSRF-Token': authenticityToken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
if (res.status === 201 || res.status === 202)
|
if (res.status === 201 || res.status === 202)
|
||||||
dispatch(likeSubmitSuccess(postId, isLike));
|
dispatch(likeSubmitSuccess(postId, isLike, json));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('An error occurred while liking a post');
|
console.log('An error occurred while liking a post');
|
||||||
}
|
}
|
||||||
|
|||||||
27
app/javascript/components/Post/LikeList.tsx
Normal file
27
app/javascript/components/Post/LikeList.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import ILike from '../../interfaces/ILike';
|
||||||
|
import Spinner from '../shared/Spinner';
|
||||||
|
import { DangerText } from '../shared/CustomTexts';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
likes: Array<ILike>;
|
||||||
|
areLoading: boolean;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LikeList = ({ likes, areLoading, error}: Props) => (
|
||||||
|
<div className="likeList">
|
||||||
|
{ areLoading ? <Spinner /> : null }
|
||||||
|
{ error ? <DangerText>{error}</DangerText> : null }
|
||||||
|
{
|
||||||
|
likes.map((like, i) => (
|
||||||
|
<div className="like" key={i}>
|
||||||
|
{like.fullName}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default LikeList;
|
||||||
@@ -4,6 +4,8 @@ import IPost from '../../interfaces/IPost';
|
|||||||
import IPostStatus from '../../interfaces/IPostStatus';
|
import IPostStatus from '../../interfaces/IPostStatus';
|
||||||
import IBoard from '../../interfaces/IBoard';
|
import IBoard from '../../interfaces/IBoard';
|
||||||
|
|
||||||
|
import LikeList from './LikeList';
|
||||||
|
import LikeButton from '../../containers/LikeButton';
|
||||||
import PostBoardSelect from './PostBoardSelect';
|
import PostBoardSelect from './PostBoardSelect';
|
||||||
import PostStatusSelect from './PostStatusSelect';
|
import PostStatusSelect from './PostStatusSelect';
|
||||||
import PostBoardLabel from '../shared/PostBoardLabel';
|
import PostBoardLabel from '../shared/PostBoardLabel';
|
||||||
@@ -12,18 +14,21 @@ import Comments from '../../containers/Comments';
|
|||||||
import { MutedText } from '../shared/CustomTexts';
|
import { MutedText } from '../shared/CustomTexts';
|
||||||
|
|
||||||
import friendlyDate from '../../helpers/friendlyDate';
|
import friendlyDate from '../../helpers/friendlyDate';
|
||||||
|
import { LikesState } from '../../reducers/likesReducer';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
postId: number;
|
postId: number;
|
||||||
post: IPost;
|
post: IPost;
|
||||||
|
likes: LikesState;
|
||||||
boards: Array<IBoard>;
|
boards: Array<IBoard>;
|
||||||
postStatuses: Array<IPostStatus>;
|
postStatuses: Array<IPostStatus>;
|
||||||
isLoggedIn: boolean;
|
isLoggedIn: boolean;
|
||||||
isPowerUser: boolean;
|
isPowerUser: boolean;
|
||||||
|
userEmail: string;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
|
|
||||||
requestPost(postId: number): void;
|
requestPost(postId: number): void;
|
||||||
|
requestLikes(postId: number): void;
|
||||||
changePostBoard(
|
changePostBoard(
|
||||||
postId: number,
|
postId: number,
|
||||||
newBoardId: number,
|
newBoardId: number,
|
||||||
@@ -39,16 +44,19 @@ interface Props {
|
|||||||
class PostP extends React.Component<Props> {
|
class PostP extends React.Component<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.requestPost(this.props.postId);
|
this.props.requestPost(this.props.postId);
|
||||||
|
this.props.requestLikes(this.props.postId);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
post,
|
post,
|
||||||
|
likes,
|
||||||
boards,
|
boards,
|
||||||
postStatuses,
|
postStatuses,
|
||||||
|
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isPowerUser,
|
isPowerUser,
|
||||||
|
userEmail,
|
||||||
authenticityToken,
|
authenticityToken,
|
||||||
|
|
||||||
changePostBoard,
|
changePostBoard,
|
||||||
@@ -58,14 +66,23 @@ class PostP extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<div className="pageContainer">
|
<div className="pageContainer">
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<div className="sidebarCard"></div>
|
<LikeList
|
||||||
<div className="sidebarCard"></div>
|
likes={likes.items}
|
||||||
<div className="sidebarCard"></div>
|
areLoading={likes.areLoading}
|
||||||
|
error={likes.error}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="postAndCommentsContainer">
|
<div className="postAndCommentsContainer">
|
||||||
<div className="postContainer">
|
<div className="postContainer">
|
||||||
<div className="postHeader">
|
<div className="postHeader">
|
||||||
|
<LikeButton
|
||||||
|
postId={post.id}
|
||||||
|
likesCount={likes.items.length}
|
||||||
|
liked={likes.items.find(like => like.email === userEmail) ? 1 : 0}
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
authenticityToken={authenticityToken}
|
||||||
|
/>
|
||||||
<h2>{post.title}</h2>
|
<h2>{post.title}</h2>
|
||||||
{
|
{
|
||||||
isPowerUser && post ?
|
isPowerUser && post ?
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ interface Props {
|
|||||||
postStatuses: Array<IPostStatus>;
|
postStatuses: Array<IPostStatus>;
|
||||||
isLoggedIn: boolean;
|
isLoggedIn: boolean;
|
||||||
isPowerUser: boolean;
|
isPowerUser: boolean;
|
||||||
|
userEmail: string;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ class PostRoot extends React.Component<Props> {
|
|||||||
postStatuses,
|
postStatuses,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isPowerUser,
|
isPowerUser,
|
||||||
|
userEmail,
|
||||||
authenticityToken
|
authenticityToken
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ class PostRoot extends React.Component<Props> {
|
|||||||
|
|
||||||
isLoggedIn={isLoggedIn}
|
isLoggedIn={isLoggedIn}
|
||||||
isPowerUser={isPowerUser}
|
isPowerUser={isPowerUser}
|
||||||
|
userEmail={userEmail}
|
||||||
authenticityToken={authenticityToken}
|
authenticityToken={authenticityToken}
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { requestPost } from '../actions/requestPost';
|
import { requestPost } from '../actions/requestPost';
|
||||||
|
import { requestLikes } from '../actions/requestLikes';
|
||||||
import { changePostBoard } from '../actions/changePostBoard';
|
import { changePostBoard } from '../actions/changePostBoard';
|
||||||
import { changePostStatus } from '../actions/changePostStatus';
|
import { changePostStatus } from '../actions/changePostStatus';
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ import PostP from '../components/Post/PostP';
|
|||||||
|
|
||||||
const mapStateToProps = (state: State) => ({
|
const mapStateToProps = (state: State) => ({
|
||||||
post: state.currentPost.item,
|
post: state.currentPost.item,
|
||||||
comments: state.currentPost.comments,
|
likes: state.currentPost.likes,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -18,6 +19,10 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
dispatch(requestPost(postId));
|
dispatch(requestPost(postId));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
requestLikes(postId: number) {
|
||||||
|
dispatch(requestLikes(postId));
|
||||||
|
},
|
||||||
|
|
||||||
changePostBoard(postId: number, newBoardId: number, authenticityToken: string) {
|
changePostBoard(postId: number, newBoardId: number, authenticityToken: string) {
|
||||||
dispatch(changePostBoard(postId, newBoardId, authenticityToken));
|
dispatch(changePostBoard(postId, newBoardId, authenticityToken));
|
||||||
},
|
},
|
||||||
|
|||||||
7
app/javascript/interfaces/ILike.ts
Normal file
7
app/javascript/interfaces/ILike.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
interface ILike {
|
||||||
|
id: number;
|
||||||
|
fullName: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ILike;
|
||||||
9
app/javascript/interfaces/json/ILike.ts
Normal file
9
app/javascript/interfaces/json/ILike.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
interface ILikeJSON {
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
post_id: number;
|
||||||
|
full_name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ILikeJSON;
|
||||||
@@ -15,6 +15,18 @@ import {
|
|||||||
CHANGE_POST_STATUS_SUCCESS,
|
CHANGE_POST_STATUS_SUCCESS,
|
||||||
} from '../actions/changePostStatus';
|
} from '../actions/changePostStatus';
|
||||||
|
|
||||||
|
import {
|
||||||
|
LikesRequestActionTypes,
|
||||||
|
LIKES_REQUEST_START,
|
||||||
|
LIKES_REQUEST_SUCCESS,
|
||||||
|
LIKES_REQUEST_FAILURE,
|
||||||
|
} from '../actions/requestLikes';
|
||||||
|
|
||||||
|
import {
|
||||||
|
LikeActionTypes,
|
||||||
|
LIKE_SUBMIT_SUCCESS,
|
||||||
|
} from '../actions/submitLike';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CommentsRequestActionTypes,
|
CommentsRequestActionTypes,
|
||||||
COMMENTS_REQUEST_START,
|
COMMENTS_REQUEST_START,
|
||||||
@@ -36,8 +48,10 @@ import {
|
|||||||
} from '../actions/submitComment';
|
} from '../actions/submitComment';
|
||||||
|
|
||||||
import postReducer from './postReducer';
|
import postReducer from './postReducer';
|
||||||
|
import likesReducer from './likesReducer';
|
||||||
import commentsReducer from './commentsReducer';
|
import commentsReducer from './commentsReducer';
|
||||||
|
|
||||||
|
import { LikesState } from './likesReducer';
|
||||||
import { CommentsState } from './commentsReducer';
|
import { CommentsState } from './commentsReducer';
|
||||||
|
|
||||||
import IPost from '../interfaces/IPost';
|
import IPost from '../interfaces/IPost';
|
||||||
@@ -46,6 +60,7 @@ interface CurrentPostState {
|
|||||||
item: IPost;
|
item: IPost;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string;
|
error: string;
|
||||||
|
likes: LikesState;
|
||||||
comments: CommentsState;
|
comments: CommentsState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +68,7 @@ const initialState: CurrentPostState = {
|
|||||||
item: postReducer(undefined, {} as PostRequestActionTypes),
|
item: postReducer(undefined, {} as PostRequestActionTypes),
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: '',
|
error: '',
|
||||||
|
likes: likesReducer(undefined, {} as LikesRequestActionTypes),
|
||||||
comments: commentsReducer(undefined, {} as CommentsRequestActionTypes),
|
comments: commentsReducer(undefined, {} as CommentsRequestActionTypes),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,6 +78,8 @@ const currentPostReducer = (
|
|||||||
PostRequestActionTypes |
|
PostRequestActionTypes |
|
||||||
ChangePostBoardSuccessAction |
|
ChangePostBoardSuccessAction |
|
||||||
ChangePostStatusSuccessAction |
|
ChangePostStatusSuccessAction |
|
||||||
|
LikesRequestActionTypes |
|
||||||
|
LikeActionTypes |
|
||||||
CommentsRequestActionTypes |
|
CommentsRequestActionTypes |
|
||||||
HandleCommentRepliesType |
|
HandleCommentRepliesType |
|
||||||
CommentSubmitActionTypes
|
CommentSubmitActionTypes
|
||||||
@@ -95,6 +113,15 @@ const currentPostReducer = (
|
|||||||
item: postReducer(state.item, action),
|
item: postReducer(state.item, action),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case LIKES_REQUEST_START:
|
||||||
|
case LIKES_REQUEST_SUCCESS:
|
||||||
|
case LIKES_REQUEST_FAILURE:
|
||||||
|
case LIKE_SUBMIT_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
likes: likesReducer(state.likes, action),
|
||||||
|
};
|
||||||
|
|
||||||
case COMMENTS_REQUEST_START:
|
case COMMENTS_REQUEST_START:
|
||||||
case COMMENTS_REQUEST_SUCCESS:
|
case COMMENTS_REQUEST_SUCCESS:
|
||||||
case COMMENTS_REQUEST_FAILURE:
|
case COMMENTS_REQUEST_FAILURE:
|
||||||
|
|||||||
82
app/javascript/reducers/likesReducer.ts
Normal file
82
app/javascript/reducers/likesReducer.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
LikesRequestActionTypes,
|
||||||
|
LIKES_REQUEST_START,
|
||||||
|
LIKES_REQUEST_SUCCESS,
|
||||||
|
LIKES_REQUEST_FAILURE,
|
||||||
|
} from '../actions/requestLikes';
|
||||||
|
|
||||||
|
import {
|
||||||
|
LikeActionTypes,
|
||||||
|
LIKE_SUBMIT_SUCCESS,
|
||||||
|
} from '../actions/submitLike';
|
||||||
|
|
||||||
|
import ILike from '../interfaces/ILike';
|
||||||
|
|
||||||
|
export interface LikesState {
|
||||||
|
items: Array<ILike>;
|
||||||
|
areLoading: boolean;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: LikesState = {
|
||||||
|
items: [],
|
||||||
|
areLoading: false,
|
||||||
|
error: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const likesReducer = (
|
||||||
|
state = initialState,
|
||||||
|
action: LikesRequestActionTypes | LikeActionTypes,
|
||||||
|
) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case LIKES_REQUEST_START:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
areLoading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case LIKES_REQUEST_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
items: action.likes.map(like => ({
|
||||||
|
id: like.id,
|
||||||
|
fullName: like.full_name,
|
||||||
|
email: like.email,
|
||||||
|
})),
|
||||||
|
areLoading: false,
|
||||||
|
error: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
case LIKES_REQUEST_FAILURE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
areLoading: false,
|
||||||
|
error: action.error,
|
||||||
|
};
|
||||||
|
|
||||||
|
case LIKE_SUBMIT_SUCCESS:
|
||||||
|
if (action.isLike) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: action.like.id,
|
||||||
|
fullName: action.like.full_name,
|
||||||
|
email: action.like.email,
|
||||||
|
},
|
||||||
|
...state.items,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
items: state.items.filter(like => like.id !== action.like.id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default likesReducer;
|
||||||
@@ -12,6 +12,12 @@
|
|||||||
.postAndCommentsContainer { width: 100%; }
|
.postAndCommentsContainer { width: 100%; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
.likeList {
|
||||||
|
@extend .sidebarCard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.postAndCommentsContainer {
|
.postAndCommentsContainer {
|
||||||
@extend
|
@extend
|
||||||
.card,
|
.card,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
postStatuses: @post_statuses,
|
postStatuses: @post_statuses,
|
||||||
isLoggedIn: user_signed_in?,
|
isLoggedIn: user_signed_in?,
|
||||||
isPowerUser: user_signed_in? ? current_user.power_user? : false,
|
isPowerUser: user_signed_in? ? current_user.power_user? : false,
|
||||||
|
userEmail: user_signed_in? ? current_user.email : nil,
|
||||||
authenticityToken: form_authenticity_token,
|
authenticityToken: form_authenticity_token,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
resources :posts, only: [:index, :create, :show, :update] do
|
resources :posts, only: [:index, :create, :show, :update] do
|
||||||
resource :likes, only: [:create, :destroy]
|
resource :likes, only: [:create, :destroy]
|
||||||
|
resources :likes, only: [:index]
|
||||||
resources :comments, only: [:index, :create]
|
resources :comments, only: [:index, :create]
|
||||||
end
|
end
|
||||||
resources :boards, only: [:show]
|
resources :boards, only: [:show]
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ require 'rails_helper'
|
|||||||
|
|
||||||
RSpec.describe 'likes routing', :aggregate_failures, type: :routing do
|
RSpec.describe 'likes routing', :aggregate_failures, type: :routing do
|
||||||
it 'routes likes' do
|
it 'routes likes' do
|
||||||
|
expect(get: '/posts/1/likes').to route_to(
|
||||||
|
controller: 'likes', action: 'index', post_id: '1'
|
||||||
|
)
|
||||||
expect(post: '/posts/1/likes').to route_to(
|
expect(post: '/posts/1/likes').to route_to(
|
||||||
controller: 'likes', action: 'create', post_id: "1"
|
controller: 'likes', action: 'create', post_id: '1'
|
||||||
)
|
)
|
||||||
expect(delete: '/posts/1/likes').to route_to(
|
expect(delete: '/posts/1/likes').to route_to(
|
||||||
controller: 'likes', action: 'destroy', post_id: "1"
|
controller: 'likes', action: 'destroy', post_id: '1'
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(get: '/posts/1/likes').not_to be_routable
|
|
||||||
expect(get: '/posts/1/likes/1').not_to be_routable
|
expect(get: '/posts/1/likes/1').not_to be_routable
|
||||||
expect(get: '/posts/1/likes/new').not_to be_routable
|
expect(get: '/posts/1/likes/new').not_to be_routable
|
||||||
expect(get: '/posts/1/likes/1/edit').not_to be_routable
|
expect(get: '/posts/1/likes/1/edit').not_to be_routable
|
||||||
|
|||||||
Reference in New Issue
Block a user