diff --git a/backend/app/Http/Controllers/ProfileController.php b/backend/app/Http/Controllers/ProfileController.php index 100fcd5..fde98d3 100755 --- a/backend/app/Http/Controllers/ProfileController.php +++ b/backend/app/Http/Controllers/ProfileController.php @@ -92,7 +92,7 @@ public function getUserDetail($userIdOrNickname) if (!$isRequestingMe) { //requesting another user, so hide their hidden cards and calculate if we are following them $cards = $cards->where(Card::FIELD_HIDDEN_TOGGLE, false); - $isFollowing = $requestorUser && $requestorUser->following->contains($user); + $isFollowing = $requestorUser && $requestorUser->followings->contains($user); } $cards = $cards->where('user_id', $user->id)->get(); @@ -119,6 +119,32 @@ public function follow($user_id) } } + /** + * authorized user follows user_id. + * Get all followers for the user. + * + * @return const RESPONSE_MESSAGE_SUCCESS or RESPONSE_MESSAGE_ALREADY_FOLLOWING + */ + public function getFollowers() + { + $user_id = auth()->user()->id; + + return response()->build(self::RESPONSE_MESSAGE_SUCCESS, User::find($user_id)->followers); + } + + /** + * authorized user follows user_id. + * Get all followings of the user. + * + * @return const RESPONSE_MESSAGE_SUCCESS or RESPONSE_MESSAGE_ALREADY_FOLLOWING + */ + public function getFollowings() + { + $user_id = auth()->user()->id; + + return response()->build(self::RESPONSE_MESSAGE_SUCCESS, User::find($user_id)->followings); + } + /** * Gets all the transactions of the user's purchases. * diff --git a/backend/app/Models/User.php b/backend/app/Models/User.php index 1a45b89..62bad9f 100755 --- a/backend/app/Models/User.php +++ b/backend/app/Models/User.php @@ -48,7 +48,7 @@ public function followers() return $this->belongsToMany('App\Models\User', 'follows', 'user_id', 'follower_id')->withTimestamps(); } - public function following() + public function followings() { return $this->belongsToMany('App\Models\User', 'follows', 'follower_id', 'user_id')->withTimestamps(); } @@ -63,7 +63,7 @@ public function following() */ public function follow($user_id) { - if (!$this->following->contains($user_id)) { + if (!$this->followings->contains($user_id)) { $user = self::findOrFail($user_id); $user->followers()->attach($this->id); diff --git a/backend/routes/api.php b/backend/routes/api.php index 7345868..f6b79c3 100755 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -22,6 +22,11 @@ Route::put('/follow/{id}', 'ProfileController@follow'); Route::get('/users', 'ProfileController@getAllUsers'); Route::get('/users/{id}', 'ProfileController@getUserDetail'); +Route::get('me/followers', 'ProfileController@getFollowers'); +Route::get('me/followings', 'ProfileController@getFollowings'); +Route::get('/test', function () { + return Route::list(); +}); Route::get('/me/transactions', 'ProfileController@getMyTransactions'); Route::get('/me/notifications', 'ProfileController@getMyNotifications'); diff --git a/frontend/src/actions/users.js b/frontend/src/actions/users.js index 7d2b1c0..ea7a5ff 100644 --- a/frontend/src/actions/users.js +++ b/frontend/src/actions/users.js @@ -152,6 +152,10 @@ export function initializeAuthFlow(address, signed) { export const REQUEST_USER_DETAIL = 'REQUEST_USER_DETAIL'; export const RECEIVE_USER_DETAIL = 'RECEIVE_USER_DETAIL'; +export const REQUEST_MY_FOLLOWINGS = 'REQUEST_MY_FOLLOWINGS'; +export const RECEIVE_MY_FOLLOWINGS = 'RECEIVE_MY_FOLLOWINGS'; +export const REQUEST_MY_FOLLOWERS = 'REQUEST_MY_FOLLOWERS'; +export const RECEIVE_MY_FOLLOWERS = 'RECEIVE_MY_FOLLOWERS'; export function fetchUserDetail(userId) { return dispatch => { @@ -244,6 +248,17 @@ export function follow(userId) { }); }; } + +export function fetchMyFollowers() { + return dispatch => { + dispatch(requestMyFollowers()); + return apiFetch('me/followers') + .then(response => response.json()) + .then(json => { + dispatch(receiveMyFollowers(json.data)); + }); + }; +} export const RECEIVE_ALL_USERS = 'RECEIVE_ALL_USERS'; export function fetchAllUsers() { @@ -256,6 +271,43 @@ export function fetchAllUsers() { }; } +function requestMyFollowers() { + return { + type: REQUEST_MY_FOLLOWERS + }; +} + +function receiveMyFollowers(followers) { + return { + type: RECEIVE_MY_FOLLOWERS, + followers + }; +} + +export function fetchMyFollowings() { + return dispatch => { + dispatch(requestMyFollowings()); + return apiFetch('me/followings') + .then(response => response.json()) + .then(json => { + dispatch(receiveMyFollowings(json.data)); + }); + }; +} + +function requestMyFollowings() { + return { + type: REQUEST_MY_FOLLOWINGS + }; +} + +function receiveMyFollowings(followings) { + return { + type: RECEIVE_MY_FOLLOWINGS, + followings + }; +} + function receiveAllUsers(users) { return { type: RECEIVE_ALL_USERS, diff --git a/frontend/src/components/FollowList.js b/frontend/src/components/FollowList.js new file mode 100644 index 0000000..3ad6335 --- /dev/null +++ b/frontend/src/components/FollowList.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; +import '../styles/App.css'; +import 'animate.css'; +import { withRouter } from 'react-router-dom'; +import { ListGroup, ListGroupItem } from 'reactstrap'; + +class FollowList extends Component { + render() { + let { follow } = this.props; + return ( +
+ {follow.map((follow, index) => { + return ( + + + {follow.nickname != null ? follow.nickname : 'Id: ' + follow.id} + + + ); + })} +
+ ); + } +} + +export default withRouter(FollowList); diff --git a/frontend/src/pages/Account.js b/frontend/src/pages/Account.js index ef0689b..6138aa0 100644 --- a/frontend/src/pages/Account.js +++ b/frontend/src/pages/Account.js @@ -3,18 +3,27 @@ import '../styles/App.scss'; import { connect } from 'react-redux'; import { Button } from 'reactstrap'; import { bindActionCreators } from 'redux'; -import { fetchMe, editMeDetails, updateMe } from '../actions/users'; +import FollowList from '../components/FollowList'; +import { + fetchMe, + editMeDetails, + updateMe, + fetchMyFollowers, + fetchUserDetail, + fetchMyFollowings +} from '../actions/users'; //Account page for update user's info class AccountPage extends Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); - this.state = { showresult: false }; } componentDidMount() { this.props.fetchMe(); + this.props.fetchMyFollowers(); + this.props.fetchMyFollowings(); } handleSubmit(e) { @@ -24,6 +33,7 @@ class AccountPage extends Component { render() { let { me } = this.props.user; + return (
@@ -91,6 +101,17 @@ class AccountPage extends Component {
+
+
+
+

Followers

+ +
+
+

Followings

+ +
+
); @@ -102,7 +123,17 @@ function mapStateToProps(state) { } const mapDispatchToProps = dispatch => { - return bindActionCreators({ fetchMe, updateMe, editMeDetails }, dispatch); + return bindActionCreators( + { + fetchMe, + updateMe, + editMeDetails, + fetchMyFollowers, + fetchUserDetail, + fetchMyFollowings + }, + dispatch + ); }; export default connect(mapStateToProps, mapDispatchToProps)(AccountPage); diff --git a/frontend/src/reducers/reducer_user.js b/frontend/src/reducers/reducer_user.js index ef41cea..71e3257 100644 --- a/frontend/src/reducers/reducer_user.js +++ b/frontend/src/reducers/reducer_user.js @@ -11,6 +11,10 @@ import { SET_SIGNED_MESSAGES, SET_WEB3_AVAILABILITY, RECEIVE_USER_DETAIL, + REQUEST_MY_FOLLOWERS, + RECEIVE_MY_FOLLOWERS, + REQUEST_MY_FOLLOWINGS, + RECEIVE_MY_FOLLOWINGS, RECEIVE_ALL_USERS } from '../actions/users'; import update from 'immutability-helper'; @@ -30,11 +34,17 @@ const INITIAL_STATE = { cards: [], cards_loading: false, + user_detail: {}, + + followers: [], + followers_loading: false, + + followings: [], + followings_loading: false, notifications: [], transactions: [], transactions_loading: false, - user_detail: {}, all_users: [] }; @@ -79,6 +89,28 @@ export default function(state = INITIAL_STATE, action) { ...state, me: action.me }; + case REQUEST_MY_FOLLOWERS: + return { + ...state, + followers_loading: true + }; + case RECEIVE_MY_FOLLOWERS: + return { + ...state, + followers: action.followers, + followers_loading: false + }; + case REQUEST_MY_FOLLOWINGS: + return { + ...state, + followings_loading: true + }; + case RECEIVE_MY_FOLLOWINGS: + return { + ...state, + followings: action.followings, + followings_loading: false + }; case REQUEST_MY_TRANSACTIONS: return { ...state,