From 0419b1189ba50a29f5c98abbd5b8bae1e4e9c253 Mon Sep 17 00:00:00 2001 From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com> Date: Sat, 29 Feb 2020 18:18:10 +0530 Subject: [PATCH 1/5] Add Sidebar in UserProfile --- package.json | 2 + .../components/UserProfileModal/UserStats.tsx | 0 src/app/components/UserProfileModal/index.tsx | 148 ++++++++++++++---- src/app/styles/UserProfileModal.module.css | 2 +- src/app/types/UserProfileModal/index.ts | 7 + 5 files changed, 131 insertions(+), 28 deletions(-) create mode 100644 src/app/components/UserProfileModal/UserStats.tsx diff --git a/package.json b/package.json index 2ef15be9..617aa02a 100644 --- a/package.json +++ b/package.json @@ -135,6 +135,7 @@ "dependencies": { "@types/commonmark": "^0.27.3", "@types/react-router-dom": "^5.1.3", + "@types/react-sidebar": "^3.0.0", "@types/reactour": "^1.13.1", "bootstrap": "^4.2.1", "classnames": "^2.2.6", @@ -158,6 +159,7 @@ "react-router": "^4.3.1", "react-router-dom": "^5.1.2", "react-router-redux": "^4.0.8", + "react-sidebar": "^3.0.2", "react-spinners": "^0.5.1", "react-split-pane": "^0.1.84", "reactour": "^1.16.0", diff --git a/src/app/components/UserProfileModal/UserStats.tsx b/src/app/components/UserProfileModal/UserStats.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/UserProfileModal/index.tsx b/src/app/components/UserProfileModal/index.tsx index 1143a63a..70daaecb 100755 --- a/src/app/components/UserProfileModal/index.tsx +++ b/src/app/components/UserProfileModal/index.tsx @@ -1,4 +1,6 @@ import PopUpMenu from 'app/components/PopUpMenu'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChartLine, faUser, faLock } from '@fortawesome/free-solid-svg-icons'; import { EditPassword } from 'app/components/UserProfileModal/EditPassword'; import { EditProfile } from 'app/components/UserProfileModal/EditProfile'; import * as styles from 'app/styles/UserProfileModal.module.css'; @@ -19,6 +21,53 @@ export class UserProfileModal extends React.Component< private editPasswordRef = React.createRef(); private reactFlagRef = React.createRef(); + public renderSwitch( + param: any, + username: any, + fullName: any, + userDetails: any, + country: any, + avatar: any, + oldPassword: any, + password: any, + repeatPassword: any, + ) { + switch (param) { + case UserProfileInterfaces.SelectedPage.EDITPROFILE: + return ( + + ); + break; + + case UserProfileInterfaces.SelectedPage.EDITPASSWORD: + return ( + + ); + break; + + default: + return

Hello World

; + } + } + constructor(props: UserProfileInterfaces.Props) { super(props); const { userDetails } = this.props; @@ -26,13 +75,13 @@ export class UserProfileModal extends React.Component< avatar: userDetails.avatar, country: userDetails.country, fullName: userDetails.fullName, + currentPage: UserProfileInterfaces.SelectedPage.EDITPROFILE, isPasswordPage: true, oldPassword: '', password: '', repeatPassword: '', username: userDetails.username, }; - this.props.getUserDetails(); } public render() { @@ -48,6 +97,55 @@ export class UserProfileModal extends React.Component< const { userDetails } = this.props; return ( +
+
{ + this.setState({ + currentPage: UserProfileInterfaces.SelectedPage.EDITPROFILE, + }); + }} + > + + +
+ +
{ + this.setState({ + currentPage: UserProfileInterfaces.SelectedPage.EDITPASSWORD, + }); + }} + > + + +
+ +
{ + this.setState({ + currentPage: UserProfileInterfaces.SelectedPage.USERSTATS, + }); + }} + > + + +
+
- {this.state.isPasswordPage ? ( - - ) : ( - + {this.renderSwitch( + this.state.currentPage, + username, + fullName, + userDetails, + country, + avatar, + oldPassword, + password, + repeatPassword, )} @@ -87,12 +173,20 @@ export class UserProfileModal extends React.Component< : classnames('labeltext', styles.passwordPageLink) } onClick={() => { - this.setState((prevState) => ({ - isPasswordPage: !prevState.isPasswordPage, - })); + let newState = + this.state.currentPage === UserProfileInterfaces.SelectedPage.EDITPROFILE + ? UserProfileInterfaces.SelectedPage.EDITPASSWORD + : UserProfileInterfaces.SelectedPage.EDITPROFILE; + this.setState({ + currentPage: newState, + }); }} > - {this.state.isPasswordPage ? 'Want to change Credentials?' : 'Want to change Info?'} + {this.state.currentPage === UserProfileInterfaces.SelectedPage.EDITPROFILE + ? 'Want to change Credentials?' + : this.state.currentPage === UserProfileInterfaces.SelectedPage.EDITPASSWORD + ? 'Want to change Info?' + : null} {this.state.isPasswordPage ? ( diff --git a/src/app/styles/UserProfileModal.module.css b/src/app/styles/UserProfileModal.module.css index a318cb77..260e797c 100755 --- a/src/app/styles/UserProfileModal.module.css +++ b/src/app/styles/UserProfileModal.module.css @@ -119,7 +119,7 @@ .passwordForm { padding: 10px 25px; width: 100%; - margin-left: 5%; + margin-left: 15%; } .profileForm { diff --git a/src/app/types/UserProfileModal/index.ts b/src/app/types/UserProfileModal/index.ts index 388829bf..4d72ceef 100644 --- a/src/app/types/UserProfileModal/index.ts +++ b/src/app/types/UserProfileModal/index.ts @@ -1,5 +1,11 @@ import * as UserInterfaces from 'app/types/User'; +export enum SelectedPage { + EDITPROFILE = 0, + EDITPASSWORD = 1, + USERSTATS = 2, +} + export interface StateProps { isUserProfileModalOpen: boolean; userDetails: UserInterfaces.UserStoreState; @@ -11,6 +17,7 @@ export interface State { oldPassword: string; password: string; repeatPassword: string; + currentPage: SelectedPage; country: string; fullName: string; isPasswordPage: boolean; From da5cf6727cb05503829bcdab1f6fbe21914d79e5 Mon Sep 17 00:00:00 2001 From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com> Date: Sat, 29 Feb 2020 22:45:04 +0530 Subject: [PATCH 2/5] Add State,Type,actions,reducers,apifetch,sagas for ProfileUser --- src/app/actions/ProfileUser.ts | 27 ++++++++ src/app/actions/index.ts | 1 + src/app/apiFetch/ProfileUser.ts | 20 ++++++ src/app/components/UserProfileModal/index.tsx | 68 ++++++++++++------- src/app/reducers/ProfileUser.ts | 46 +++++++++++++ src/app/reducers/index.ts | 4 ++ src/app/sagas/ProfileUser.ts | 29 ++++++++ src/app/types/ProfileUser.ts | 44 ++++++++++++ src/app/types/User.ts | 10 +++ 9 files changed, 225 insertions(+), 24 deletions(-) create mode 100644 src/app/actions/ProfileUser.ts create mode 100644 src/app/apiFetch/ProfileUser.ts create mode 100644 src/app/reducers/ProfileUser.ts create mode 100644 src/app/sagas/ProfileUser.ts create mode 100644 src/app/types/ProfileUser.ts diff --git a/src/app/actions/ProfileUser.ts b/src/app/actions/ProfileUser.ts new file mode 100644 index 00000000..f2263bd6 --- /dev/null +++ b/src/app/actions/ProfileUser.ts @@ -0,0 +1,27 @@ +import * as ProfileUserInterfaces from 'app/types/User'; +import { action } from 'typesafe-actions'; + +export namespace ProfileUserActions { + export enum Type { + GET_PROFILE_USER_DETAILS = 'GET_USER_DETAILS', + GET_MATCH_STATS = 'GET_MATCH_STATS', + UPDATE_PROFILE_USER_DETAILS = 'UPDATE_PROFILE_USER_DETAILS', + } + + interface ProfileUserDetails { + avatar?: string; + college?: string; + userType?: ProfileUserInterfaces.UserType; + fullName?: string; + username?: string; + email?: string; + country?: string; + } + + export const updateUserDetails = (profileuserDetails: ProfileUserDetails) => + action(Type.UPDATE_PROFILE_USER_DETAILS, { profileuserDetails }); + + export const getUserDetails = () => action(Type.GET_PROFILE_USER_DETAILS); + + export const getMatchStats = (username: string) => action(Type.GET_MATCH_STATS, { username }); +} diff --git a/src/app/actions/index.ts b/src/app/actions/index.ts index dfbe67ac..77013486 100644 --- a/src/app/actions/index.ts +++ b/src/app/actions/index.ts @@ -7,3 +7,4 @@ export * from 'app/actions/User'; export * from 'app/actions/Notification'; export * from 'app/actions/code/Submission'; export * from 'app/actions/MatchView'; +export * from 'app/actions/ProfileUser'; diff --git a/src/app/apiFetch/ProfileUser.ts b/src/app/apiFetch/ProfileUser.ts new file mode 100644 index 00000000..5c3b6c81 --- /dev/null +++ b/src/app/apiFetch/ProfileUser.ts @@ -0,0 +1,20 @@ +/* tslint:disable:no-console*/ +import { jsonResponseWrapper } from 'app/apiFetch/utils'; +import { API_BASE_URL } from '../../config/config'; + +export const getMatchStats = (username: string) => { + const URL = `${API_BASE_URL}/match-stats/${encodeURIComponent(username)}`; + return fetch(URL, { + credentials: 'include', + method: 'GET', + }) + .then((response) => { + return jsonResponseWrapper(response); + }) + .then((data) => { + return data; + }) + .catch((error) => { + console.error(error); + }); +}; diff --git a/src/app/components/UserProfileModal/index.tsx b/src/app/components/UserProfileModal/index.tsx index 70daaecb..cc93edee 100755 --- a/src/app/components/UserProfileModal/index.tsx +++ b/src/app/components/UserProfileModal/index.tsx @@ -1,6 +1,11 @@ +<<<<<<< HEAD import PopUpMenu from 'app/components/PopUpMenu'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChartLine, faUser, faLock } from '@fortawesome/free-solid-svg-icons'; +======= +import { faChartLine, faLock, faUser } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +>>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser import { EditPassword } from 'app/components/UserProfileModal/EditPassword'; import { EditProfile } from 'app/components/UserProfileModal/EditProfile'; import * as styles from 'app/styles/UserProfileModal.module.css'; @@ -21,16 +26,33 @@ export class UserProfileModal extends React.Component< private editPasswordRef = React.createRef(); private reactFlagRef = React.createRef(); + constructor(props: UserProfileInterfaces.Props) { + super(props); + const { userDetails } = this.props; + this.state = { + avatar: userDetails.avatar, + country: userDetails.country, + currentPage: UserProfileInterfaces.SelectedPage.EDITPROFILE, + fullName: userDetails.fullName, + isPasswordPage: true, + oldPassword: '', + password: '', + repeatPassword: '', + username: userDetails.username, + }; + } + public renderSwitch( - param: any, - username: any, - fullName: any, + param: UserProfileInterfaces.SelectedPage, + username: string, + fullName: string, + // tslint:disable-next-line userDetails: any, - country: any, - avatar: any, - oldPassword: any, - password: any, - repeatPassword: any, + country: string, + avatar: string, + oldPassword: string, + password: string, + repeatPassword: string, ) { switch (param) { case UserProfileInterfaces.SelectedPage.EDITPROFILE: @@ -68,22 +90,6 @@ export class UserProfileModal extends React.Component< } } - constructor(props: UserProfileInterfaces.Props) { - super(props); - const { userDetails } = this.props; - this.state = { - avatar: userDetails.avatar, - country: userDetails.country, - fullName: userDetails.fullName, - currentPage: UserProfileInterfaces.SelectedPage.EDITPROFILE, - isPasswordPage: true, - oldPassword: '', - password: '', - repeatPassword: '', - username: userDetails.username, - }; - } - public render() { const { fullName, @@ -99,6 +105,7 @@ export class UserProfileModal extends React.Component<
>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser }} >
{ +<<<<<<< HEAD let newState = +======= + const newState = +>>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser this.state.currentPage === UserProfileInterfaces.SelectedPage.EDITPROFILE ? UserProfileInterfaces.SelectedPage.EDITPASSWORD : UserProfileInterfaces.SelectedPage.EDITPROFILE; diff --git a/src/app/reducers/ProfileUser.ts b/src/app/reducers/ProfileUser.ts new file mode 100644 index 00000000..8999c203 --- /dev/null +++ b/src/app/reducers/ProfileUser.ts @@ -0,0 +1,46 @@ +import { ProfileUserActions } from 'app/actions'; +import * as ProfileUserInterfaces from 'app/types/ProfileUser'; + +const profileStoreIntialState: ProfileUserInterfaces.ProfileUserStoreState = { + avatar: '', + college: '', + country: 'IN', + email: '', + fullName: '', + type: '', + userType: ProfileUserInterfaces.ProfileUserType.STUDENT, + username: '', +}; + +export const profileuserReducer = ( + state = profileStoreIntialState, + action: ProfileUserInterfaces.ProfileUserStoreAction, +) => { + switch (action.type) { + case ProfileUserActions.Type.UPDATE_PROFILE_USER_DETAILS: { + const { + avatar, + college, + country, + email, + fullName, + userType, + username, + } = action.payload.profileuserDetails; + + return { + ...state, + avatar: avatar !== undefined ? avatar : state.avatar, + college: college !== undefined ? college : state.college, + country: country !== undefined ? country : state.country, + email: email !== undefined ? email : state.email, + fullName: fullName !== undefined ? fullName : state.fullName, + type: userType !== undefined ? userType : state.type, + username: username !== undefined ? username : state.username, + }; + } + + default: + return state; + } +}; diff --git a/src/app/reducers/index.ts b/src/app/reducers/index.ts index da6d5d64..796adedb 100644 --- a/src/app/reducers/index.ts +++ b/src/app/reducers/index.ts @@ -6,6 +6,7 @@ import { gameLogReducer } from 'app/reducers/GameLog'; import { leaderboardReducer } from 'app/reducers/Leaderboard'; import { matchesReducer } from 'app/reducers/MatchView'; import { notificationReducer } from 'app/reducers/Notification'; +import { profileuserReducer } from 'app/reducers/ProfileUser'; import { userReducer } from 'app/reducers/User'; import * as CodeInterfaces from 'app/types/code/Code'; import * as EditorInterfaces from 'app/types/code/Editor'; @@ -15,6 +16,7 @@ import * as GameLogInterfaces from 'app/types/GameLog'; import * as LeaderboardInterfaces from 'app/types/Leaderboard'; import * as MatchInterfaces from 'app/types/MatchView'; import * as NotificationInterfaces from 'app/types/Notification'; +import * as ProfileUserInterfaces from 'app/types/ProfileUser'; import * as UserInterfaces from 'app/types/User'; import { routerReducer, RouterState } from 'react-router-redux'; import { combineReducers } from 'redux'; @@ -27,6 +29,7 @@ export const rootReducer = combineReducers({ leaderboard: leaderboardReducer, match: matchesReducer, notification: notificationReducer, + profileUser: profileuserReducer, router: routerReducer, submission: submissionReducer, user: userReducer, @@ -42,5 +45,6 @@ export interface RootState { router: RouterState; gameLog: GameLogInterfaces.GameLogStoreState; user: UserInterfaces.UserStoreState; + profileuser: ProfileUserInterfaces.ProfileUserStoreState; submission: SubmissionInterfaces.SubmissionStoreState; } diff --git a/src/app/sagas/ProfileUser.ts b/src/app/sagas/ProfileUser.ts new file mode 100644 index 00000000..68722906 --- /dev/null +++ b/src/app/sagas/ProfileUser.ts @@ -0,0 +1,29 @@ +/* tslint:disable:no-console*/ +import { ProfileUserActions, UserActions } from 'app/actions'; +import * as ProfileUserFetch from 'app/apiFetch/ProfileUser'; +import { avatarName } from 'app/types/Authentication/Register'; +import { resType } from 'app/types/sagas'; +import { call, put } from 'redux-saga/effects'; +import { ActionType } from 'typesafe-actions'; + +export function* getMatchStats(action: ActionType) { + try { + const res = yield call(ProfileUserFetch.getMatchStats, action.payload.username); + yield put(UserActions.updateErrorMessage(res.error)); + if (res.type !== resType.ERROR) { + const { avatarId, college, country, fullName, userType, username } = res.body; + yield put( + ProfileUserActions.updateUserDetails({ + college, + country, + fullName, + userType, + username, + avatar: avatarName[avatarId], + }), + ); + } + } catch (err) { + console.error(err); + } +} diff --git a/src/app/types/ProfileUser.ts b/src/app/types/ProfileUser.ts new file mode 100644 index 00000000..9c57e660 --- /dev/null +++ b/src/app/types/ProfileUser.ts @@ -0,0 +1,44 @@ +import { ProfileUserActions } from 'app/actions'; +import { ActionType } from 'typesafe-actions'; + +export enum ProfileUserType { + STUDENT = 'STUDENT', + PROFESSIONAL = 'PROFESSIONAL', +} + +export interface EditProfileUserDetails { + username?: string; + email?: string; + country?: string; + fullName?: string; + college?: string; + type?: string; + avatar?: string; +} + +const actions = { + getUserDetails: ProfileUserActions.getUserDetails, + updateUserDetails: ProfileUserActions.updateUserDetails, +}; + +export interface ProfileUserStoreState { + fullName: string; + username: string; + email: string; + country: string; + college: string; + userType: ProfileUserType; + avatar: string; +} + +export interface ProfileUserStoreState { + avatar: string; + college: string; + country: string; + email: string; + fullName: string; + type: string; + username: string; +} + +export type ProfileUserStoreAction = ActionType; diff --git a/src/app/types/User.ts b/src/app/types/User.ts index 99e8ab1a..8af4e35c 100644 --- a/src/app/types/User.ts +++ b/src/app/types/User.ts @@ -71,4 +71,14 @@ export interface UserStoreState { avatar: string; } +export interface ProfileUserStoreState { + avatar: string; + college: string; + country: string; + email: string; + fullName: string; + type: string; + username: string; +} + export type UserStoreAction = ActionType; From a8d702e7e8013109f9995e9a47cee5e160154c4f Mon Sep 17 00:00:00 2001 From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com> Date: Sun, 1 Mar 2020 01:24:59 +0530 Subject: [PATCH 3/5] Add route for /profile/:user and Add the required container --- src/app/actions/ProfileUser.ts | 2 +- src/app/apiFetch/ProfileUser.ts | 2 +- .../Leaderboard/LeaderboardElement.tsx | 14 +++++--- src/app/components/ProfileUserStats.tsx | 8 +++++ .../components/UserProfileModal/UserStats.tsx | 7 ++++ src/app/components/UserProfileModal/index.tsx | 26 ++++----------- src/app/containers/ProfileUsersStats.ts | 33 +++++++++++++++++++ src/app/index.tsx | 5 +++ src/app/reducers/index.ts | 2 +- src/app/routes.ts | 4 +++ src/app/sagas/ProfileUser.ts | 2 +- src/app/types/ProfileUser.ts | 24 +++++++------- 12 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 src/app/components/ProfileUserStats.tsx create mode 100644 src/app/containers/ProfileUsersStats.ts diff --git a/src/app/actions/ProfileUser.ts b/src/app/actions/ProfileUser.ts index f2263bd6..cfdaec84 100644 --- a/src/app/actions/ProfileUser.ts +++ b/src/app/actions/ProfileUser.ts @@ -18,7 +18,7 @@ export namespace ProfileUserActions { country?: string; } - export const updateUserDetails = (profileuserDetails: ProfileUserDetails) => + export const updateProfileUserDetails = (profileuserDetails: ProfileUserDetails) => action(Type.UPDATE_PROFILE_USER_DETAILS, { profileuserDetails }); export const getUserDetails = () => action(Type.GET_PROFILE_USER_DETAILS); diff --git a/src/app/apiFetch/ProfileUser.ts b/src/app/apiFetch/ProfileUser.ts index 5c3b6c81..79dc5e28 100644 --- a/src/app/apiFetch/ProfileUser.ts +++ b/src/app/apiFetch/ProfileUser.ts @@ -3,7 +3,7 @@ import { jsonResponseWrapper } from 'app/apiFetch/utils'; import { API_BASE_URL } from '../../config/config'; export const getMatchStats = (username: string) => { - const URL = `${API_BASE_URL}/match-stats/${encodeURIComponent(username)}`; + const URL = `${API_BASE_URL}user/match-stats/${encodeURIComponent(username)}`; return fetch(URL, { credentials: 'include', method: 'GET', diff --git a/src/app/components/Leaderboard/LeaderboardElement.tsx b/src/app/components/Leaderboard/LeaderboardElement.tsx index 257a59b9..9e9c9bae 100644 --- a/src/app/components/Leaderboard/LeaderboardElement.tsx +++ b/src/app/components/Leaderboard/LeaderboardElement.tsx @@ -16,7 +16,11 @@ const colors = ['#FFB900', '#69797E', '#847545', '#038387']; export class LeaderboardElement extends React.Component { public render() { const { player, index, isPlayAgainstDisabled, runMatch, currentUsername } = this.props; - + if (player.username === currentUsername) { + const urlToProfile = `/profile`; + } else { + const urlToProfile = `/profile/${player.username}`; + } const playerTotalMatches = player.numWin + player.numLoss + player.numTie; return ( @@ -86,9 +90,11 @@ export class LeaderboardElement extends React.Component - {`${player.username.substr(0, 15)}${ - player.username.length > 15 ? '...' : '' - }`} + + {`${player.username.substr(0, 15)}${ + player.username.length > 15 ? '...' : '' + }`} +
{ + public render() { + return

This is the Page for Profile user stats

; + } +} diff --git a/src/app/components/UserProfileModal/UserStats.tsx b/src/app/components/UserProfileModal/UserStats.tsx index e69de29b..f8e58b1e 100644 --- a/src/app/components/UserProfileModal/UserStats.tsx +++ b/src/app/components/UserProfileModal/UserStats.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; + +export class UserStats extends React.Component { + public render() { + return

This is the Page for Current user stats

; + } +} diff --git a/src/app/components/UserProfileModal/index.tsx b/src/app/components/UserProfileModal/index.tsx index cc93edee..a39b9a5a 100755 --- a/src/app/components/UserProfileModal/index.tsx +++ b/src/app/components/UserProfileModal/index.tsx @@ -1,13 +1,9 @@ -<<<<<<< HEAD import PopUpMenu from 'app/components/PopUpMenu'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChartLine, faUser, faLock } from '@fortawesome/free-solid-svg-icons'; -======= -import { faChartLine, faLock, faUser } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; ->>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser import { EditPassword } from 'app/components/UserProfileModal/EditPassword'; import { EditProfile } from 'app/components/UserProfileModal/EditProfile'; +import { UserStats } from 'app/components/UserProfileModal/UserStats'; import * as styles from 'app/styles/UserProfileModal.module.css'; import { AvatarId } from 'app/types/Authentication/Register'; import * as UserProfileInterfaces from 'app/types/UserProfileModal'; @@ -85,8 +81,12 @@ export class UserProfileModal extends React.Component< ); break; + case UserProfileInterfaces.SelectedPage.USERSTATS: + return ; + break; + default: - return

Hello World

; + return

Default

; } } @@ -105,15 +105,6 @@ export class UserProfileModal extends React.Component<
>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser }} >
{ -<<<<<<< HEAD - let newState = -======= const newState = ->>>>>>> Add State,Type,actions,reducers,apifetch,sagas for ProfileUser this.state.currentPage === UserProfileInterfaces.SelectedPage.EDITPROFILE ? UserProfileInterfaces.SelectedPage.EDITPASSWORD : UserProfileInterfaces.SelectedPage.EDITPROFILE; diff --git a/src/app/containers/ProfileUsersStats.ts b/src/app/containers/ProfileUsersStats.ts new file mode 100644 index 00000000..25595812 --- /dev/null +++ b/src/app/containers/ProfileUsersStats.ts @@ -0,0 +1,33 @@ +import { ProfileUserActions } from 'app/actions'; +import { ProfileUserStats } from 'app/components/ProfileUserStats'; +import { RootState } from 'app/reducers'; +import * as ProfileUserInterfaces from 'app/types/ProfileUser'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +const mapStateToProps = (rootState: RootState) => { + return { + profileUserDetails: rootState.profileUser, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch) => { + return { + getMatchStats: (username: string) => dispatch(ProfileUserActions.getMatchStats(username)), + getUserDetails: () => dispatch(ProfileUserActions.getUserDetails()), + updateProfileUserDetails: ( + updateProfileUserDetails: ProfileUserInterfaces.EditProfileUserDetails, + ) => dispatch(ProfileUserActions.updateProfileUserDetails(updateProfileUserDetails)), + }; +}; + +const profileUserContainer = connect< + ProfileUserInterfaces.StateProps, + ProfileUserInterfaces.DispatchProps, + {} +>( + mapStateToProps, + mapDispatchToProps, +)(ProfileUserStats); + +export default profileUserContainer; diff --git a/src/app/index.tsx b/src/app/index.tsx index d70d20c7..b88e4c13 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -4,6 +4,7 @@ import Register from 'app/containers/Authentication/Register'; import Dashboard from 'app/containers/Dashboard'; import Leaderboard from 'app/containers/Leaderboard'; import UserProfileModal from 'app/containers/UserProfileModal'; +import profileUserContainer from 'app/containers/ProfileUsersStats' import { Routes } from 'app/routes'; // @ts-ignore import { initializeRendererAssets } from 'codecharacter-renderer'; @@ -24,7 +25,11 @@ export const App = hot(module)(() => ( +<<<<<<< HEAD +======= + +>>>>>>> Add route for /profile/:user and Add the required container diff --git a/src/app/reducers/index.ts b/src/app/reducers/index.ts index 796adedb..eba805d7 100644 --- a/src/app/reducers/index.ts +++ b/src/app/reducers/index.ts @@ -45,6 +45,6 @@ export interface RootState { router: RouterState; gameLog: GameLogInterfaces.GameLogStoreState; user: UserInterfaces.UserStoreState; - profileuser: ProfileUserInterfaces.ProfileUserStoreState; + profileUser: ProfileUserInterfaces.ProfileUserStoreState; submission: SubmissionInterfaces.SubmissionStoreState; } diff --git a/src/app/routes.ts b/src/app/routes.ts index 7b0c8cb8..8714c769 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -4,7 +4,11 @@ export enum Routes { REGISTER = '/register', LEADERBOARD = '/leaderboard', USER_PROFILE_MODEL = '/profile', +<<<<<<< HEAD GITHUB_OAUTH = '/login/github', GOOGLE_OAUTH = '/login/google', USER_ACTIVATION = '/user-activate', +======= + PROFILE_USER_STATS = '/profile/:username', +>>>>>>> Add route for /profile/:user and Add the required container } diff --git a/src/app/sagas/ProfileUser.ts b/src/app/sagas/ProfileUser.ts index 68722906..d2186cf6 100644 --- a/src/app/sagas/ProfileUser.ts +++ b/src/app/sagas/ProfileUser.ts @@ -13,7 +13,7 @@ export function* getMatchStats(action: ActionType void; + getUserDetails: () => void; + getMatchStats: (username: string) => void; +} +export type Props = StateProps & DispatchProps; + export type ProfileUserStoreAction = ActionType; From 41edbf3a1fc096915727bd222fadab94ddd7c93d Mon Sep 17 00:00:00 2001 From: Chethan2k1 <40890937+Chethan2k1@users.noreply.github.com> Date: Sun, 1 Mar 2020 11:29:49 +0530 Subject: [PATCH 4/5] Change the Route for profile user stats --- src/app/components/Leaderboard/LeaderboardElement.tsx | 5 +++-- src/app/components/ProfileUserStats.tsx | 5 +++-- src/app/containers/ProfileUsersStats.ts | 2 +- src/app/index.tsx | 7 ++----- src/app/routes.ts | 5 +---- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/app/components/Leaderboard/LeaderboardElement.tsx b/src/app/components/Leaderboard/LeaderboardElement.tsx index 9e9c9bae..d8025d3e 100644 --- a/src/app/components/Leaderboard/LeaderboardElement.tsx +++ b/src/app/components/Leaderboard/LeaderboardElement.tsx @@ -16,10 +16,11 @@ const colors = ['#FFB900', '#69797E', '#847545', '#038387']; export class LeaderboardElement extends React.Component { public render() { const { player, index, isPlayAgainstDisabled, runMatch, currentUsername } = this.props; + let urlToProfile; if (player.username === currentUsername) { - const urlToProfile = `/profile`; + urlToProfile = `/profile`; } else { - const urlToProfile = `/profile/${player.username}`; + urlToProfile = `/profile/${player.username}`; } const playerTotalMatches = player.numWin + player.numLoss + player.numTie; diff --git a/src/app/components/ProfileUserStats.tsx b/src/app/components/ProfileUserStats.tsx index 1c13391e..1b0f5b43 100644 --- a/src/app/components/ProfileUserStats.tsx +++ b/src/app/components/ProfileUserStats.tsx @@ -1,8 +1,9 @@ import * as ProfileUserInterface from 'app/types/ProfileUser'; import * as React from 'react'; -export class ProfileUserStats extends React.Component { +export default class ProfileUserStats extends React.Component { public render() { + console.log(this.props.match.params.username); return

This is the Page for Profile user stats

; - } + } } diff --git a/src/app/containers/ProfileUsersStats.ts b/src/app/containers/ProfileUsersStats.ts index 25595812..4e5de23b 100644 --- a/src/app/containers/ProfileUsersStats.ts +++ b/src/app/containers/ProfileUsersStats.ts @@ -1,5 +1,5 @@ import { ProfileUserActions } from 'app/actions'; -import { ProfileUserStats } from 'app/components/ProfileUserStats'; +import ProfileUserStats from 'app/components/ProfileUserStats'; import { RootState } from 'app/reducers'; import * as ProfileUserInterfaces from 'app/types/ProfileUser'; import { connect } from 'react-redux'; diff --git a/src/app/index.tsx b/src/app/index.tsx index b88e4c13..deb98878 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -3,8 +3,8 @@ import Login from 'app/containers/Authentication/Login'; import Register from 'app/containers/Authentication/Register'; import Dashboard from 'app/containers/Dashboard'; import Leaderboard from 'app/containers/Leaderboard'; +import ProfileUsersStats from 'app/containers/ProfileUsersStats'; import UserProfileModal from 'app/containers/UserProfileModal'; -import profileUserContainer from 'app/containers/ProfileUsersStats' import { Routes } from 'app/routes'; // @ts-ignore import { initializeRendererAssets } from 'codecharacter-renderer'; @@ -25,11 +25,8 @@ export const App = hot(module)(() => ( -<<<<<<< HEAD -======= - ->>>>>>> Add route for /profile/:user and Add the required container + diff --git a/src/app/routes.ts b/src/app/routes.ts index 8714c769..2e78403e 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -4,11 +4,8 @@ export enum Routes { REGISTER = '/register', LEADERBOARD = '/leaderboard', USER_PROFILE_MODEL = '/profile', -<<<<<<< HEAD GITHUB_OAUTH = '/login/github', GOOGLE_OAUTH = '/login/google', USER_ACTIVATION = '/user-activate', -======= - PROFILE_USER_STATS = '/profile/:username', ->>>>>>> Add route for /profile/:user and Add the required container + PROFILE_USER_STATS = '/:username', } From f2ce679a33957738fdf673d61eda42730c235620 Mon Sep 17 00:00:00 2001 From: Bestin Date: Mon, 2 Mar 2020 20:15:12 +0530 Subject: [PATCH 5/5] fixup! Change the Route for profile user stats --- package.json | 2 +- src/app/actions/ProfileUser.ts | 12 ++++++-- src/app/apiFetch/ProfileUser.ts | 25 +++++++++++++++++ src/app/components/ProfileUserStats.tsx | 18 ++++++++++-- src/app/components/UserProfileModal/index.tsx | 4 +-- src/app/containers/ProfileUsersStats.ts | 2 +- src/app/reducers/ProfileUser.ts | 15 ++++++++++ src/app/routes.ts | 2 +- src/app/sagas/ProfileUser.ts | 21 +++++++++++++- src/app/store/index.ts | 2 ++ src/app/types/ProfileUser.ts | 28 +++++++++++++++++-- 11 files changed, 117 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 617aa02a..b9b62389 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "predeploy": "npm run build", "test": "jest -i", - "start": "webpack-dev-server --mode development --hot --progress --color --port 3000", + "start": "webpack-dev-server --mode development --hot --progress --color --port 3000 --host 0.0.0.0", "build": "webpack -p --progress --colors", "lint": "prettier --write \"src/**/*.{ts,tsx,css}\" \"__tests__/**/*.{ts,tsx,css}\" && tslint --project .", "lint:fix": "tslint --project . --fix" diff --git a/src/app/actions/ProfileUser.ts b/src/app/actions/ProfileUser.ts index cfdaec84..3f2c3c6d 100644 --- a/src/app/actions/ProfileUser.ts +++ b/src/app/actions/ProfileUser.ts @@ -1,4 +1,5 @@ -import * as ProfileUserInterfaces from 'app/types/User'; +import * as ProfileInterfaces from 'app/types/ProfileUser'; +import * as UserInterfaces from 'app/types/User'; import { action } from 'typesafe-actions'; export namespace ProfileUserActions { @@ -6,12 +7,13 @@ export namespace ProfileUserActions { GET_PROFILE_USER_DETAILS = 'GET_USER_DETAILS', GET_MATCH_STATS = 'GET_MATCH_STATS', UPDATE_PROFILE_USER_DETAILS = 'UPDATE_PROFILE_USER_DETAILS', + UPDATE_MATCH_STATS = 'UPDATE_MATCH_STATS', } interface ProfileUserDetails { avatar?: string; college?: string; - userType?: ProfileUserInterfaces.UserType; + userType?: UserInterfaces.UserType; fullName?: string; username?: string; email?: string; @@ -21,7 +23,11 @@ export namespace ProfileUserActions { export const updateProfileUserDetails = (profileuserDetails: ProfileUserDetails) => action(Type.UPDATE_PROFILE_USER_DETAILS, { profileuserDetails }); - export const getUserDetails = () => action(Type.GET_PROFILE_USER_DETAILS); + export const getUserDetails = (username: string) => + action(Type.GET_PROFILE_USER_DETAILS, { username }); + + export const updateMatchStats = (matchStats: ProfileInterfaces.ProfileMatchStats) => + action(Type.UPDATE_MATCH_STATS, { matchStats }); export const getMatchStats = (username: string) => action(Type.GET_MATCH_STATS, { username }); } diff --git a/src/app/apiFetch/ProfileUser.ts b/src/app/apiFetch/ProfileUser.ts index 79dc5e28..4bb982ee 100644 --- a/src/app/apiFetch/ProfileUser.ts +++ b/src/app/apiFetch/ProfileUser.ts @@ -9,9 +9,34 @@ export const getMatchStats = (username: string) => { method: 'GET', }) .then((response) => { + console.log('fetch match response'); + console.log(response); return jsonResponseWrapper(response); }) .then((data) => { + console.log('fetch match data'); + console.log(data); + return data; + }) + .catch((error) => { + console.error(error); + }); +}; + +export const getUserProfile = (username: string) => { + const URL = `${API_BASE_URL}user/${username}`; + return fetch(URL, { + credentials: 'include', + method: 'GET', + }) + .then((response) => { + console.log('fetch profile response'); + console.log(response); + return jsonResponseWrapper(response); + }) + .then((data) => { + console.log('fetch profile data'); + console.log(data); return data; }) .catch((error) => { diff --git a/src/app/components/ProfileUserStats.tsx b/src/app/components/ProfileUserStats.tsx index 1b0f5b43..35223ec9 100644 --- a/src/app/components/ProfileUserStats.tsx +++ b/src/app/components/ProfileUserStats.tsx @@ -1,9 +1,21 @@ +import { Avatar } from 'app/types/Authentication/Register'; import * as ProfileUserInterface from 'app/types/ProfileUser'; import * as React from 'react'; export default class ProfileUserStats extends React.Component { + public componentDidMount() { + this.props.getUserDetails(''); + this.props.getMatchStats(this.props.match.params.username); + } public render() { - console.log(this.props.match.params.username); - return

This is the Page for Profile user stats

; - } + // console.log(this.props.profileUserDetails); + return ( +
+ { + // @ts-ignore + + } +
+ ); + } } diff --git a/src/app/components/UserProfileModal/index.tsx b/src/app/components/UserProfileModal/index.tsx index a39b9a5a..65b5f31e 100755 --- a/src/app/components/UserProfileModal/index.tsx +++ b/src/app/components/UserProfileModal/index.tsx @@ -1,6 +1,6 @@ -import PopUpMenu from 'app/components/PopUpMenu'; +import { faChartLine, faLock, faUser } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faChartLine, faUser, faLock } from '@fortawesome/free-solid-svg-icons'; +import PopUpMenu from 'app/components/PopUpMenu'; import { EditPassword } from 'app/components/UserProfileModal/EditPassword'; import { EditProfile } from 'app/components/UserProfileModal/EditProfile'; import { UserStats } from 'app/components/UserProfileModal/UserStats'; diff --git a/src/app/containers/ProfileUsersStats.ts b/src/app/containers/ProfileUsersStats.ts index 4e5de23b..6384b5aa 100644 --- a/src/app/containers/ProfileUsersStats.ts +++ b/src/app/containers/ProfileUsersStats.ts @@ -14,7 +14,7 @@ const mapStateToProps = (rootState: RootState) => { const mapDispatchToProps = (dispatch: Dispatch) => { return { getMatchStats: (username: string) => dispatch(ProfileUserActions.getMatchStats(username)), - getUserDetails: () => dispatch(ProfileUserActions.getUserDetails()), + getUserDetails: (username: string) => dispatch(ProfileUserActions.getUserDetails(username)), updateProfileUserDetails: ( updateProfileUserDetails: ProfileUserInterfaces.EditProfileUserDetails, ) => dispatch(ProfileUserActions.updateProfileUserDetails(updateProfileUserDetails)), diff --git a/src/app/reducers/ProfileUser.ts b/src/app/reducers/ProfileUser.ts index 8999c203..368f2bce 100644 --- a/src/app/reducers/ProfileUser.ts +++ b/src/app/reducers/ProfileUser.ts @@ -7,6 +7,14 @@ const profileStoreIntialState: ProfileUserInterfaces.ProfileUserStoreState = { country: 'IN', email: '', fullName: '', + matchStats: { + auto: { wins: 0, losses: 0, ties: 0 }, + faced: { wins: 0, losses: 0, ties: 0 }, + initiated: { wins: 0, losses: 0, ties: 0 }, + lastMatchAt: '', + numMatchches: 0, + userId: 0, + }, type: '', userType: ProfileUserInterfaces.ProfileUserType.STUDENT, username: '', @@ -40,6 +48,13 @@ export const profileuserReducer = ( }; } + case ProfileUserActions.Type.UPDATE_MATCH_STATS: { + return { + ...state, + matchStats: action.payload.matchStats, + }; + } + default: return state; } diff --git a/src/app/routes.ts b/src/app/routes.ts index 2e78403e..d919b842 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -7,5 +7,5 @@ export enum Routes { GITHUB_OAUTH = '/login/github', GOOGLE_OAUTH = '/login/google', USER_ACTIVATION = '/user-activate', - PROFILE_USER_STATS = '/:username', + PROFILE_USER_STATS = '/profile::username', } diff --git a/src/app/sagas/ProfileUser.ts b/src/app/sagas/ProfileUser.ts index d2186cf6..f8ae3e32 100644 --- a/src/app/sagas/ProfileUser.ts +++ b/src/app/sagas/ProfileUser.ts @@ -3,13 +3,15 @@ import { ProfileUserActions, UserActions } from 'app/actions'; import * as ProfileUserFetch from 'app/apiFetch/ProfileUser'; import { avatarName } from 'app/types/Authentication/Register'; import { resType } from 'app/types/sagas'; -import { call, put } from 'redux-saga/effects'; +import { all, call, put, takeEvery } from 'redux-saga/effects'; import { ActionType } from 'typesafe-actions'; export function* getMatchStats(action: ActionType) { try { const res = yield call(ProfileUserFetch.getMatchStats, action.payload.username); yield put(UserActions.updateErrorMessage(res.error)); + console.log('saga match res'); + console.log(res); if (res.type !== resType.ERROR) { const { avatarId, college, country, fullName, userType, username } = res.body; yield put( @@ -27,3 +29,20 @@ export function* getMatchStats(action: ActionType) { + try { + const res = yield call(ProfileUserFetch.getUserProfile, action.payload.username); + console.log('saga profile res'); + console.log(res); + } catch (err) { + console.error(err); + } +} + +export function* profileSagas() { + yield all([ + takeEvery(ProfileUserActions.Type.GET_MATCH_STATS, getMatchStats), + takeEvery(ProfileUserActions.Type.GET_PROFILE_USER_DETAILS, getUserProfile), + ]); +} diff --git a/src/app/store/index.ts b/src/app/store/index.ts index 8fb448fe..1f792b4b 100644 --- a/src/app/store/index.ts +++ b/src/app/store/index.ts @@ -4,6 +4,7 @@ import { codeSagas } from 'app/sagas/Code'; import { leaderboardSagas } from 'app/sagas/Leaderboard'; import { matchSagas } from 'app/sagas/MatchView'; import { notificationSagas } from 'app/sagas/Notification'; +import { profileSagas } from 'app/sagas/ProfileUser'; import { submissionSagas } from 'app/sagas/Submission'; import { userSagas } from 'app/sagas/User'; import { applyMiddleware, createStore } from 'redux'; @@ -32,6 +33,7 @@ export function configureStore(initialState?: object) { const store = createStore(persistedReducer, initialState, middleware); sagaMiddleware.run(userSagas); sagaMiddleware.run(codeSagas); + sagaMiddleware.run(profileSagas); sagaMiddleware.run(leaderboardSagas); sagaMiddleware.run(submissionSagas); sagaMiddleware.run(matchSagas); diff --git a/src/app/types/ProfileUser.ts b/src/app/types/ProfileUser.ts index a36a0a1c..3a90a834 100644 --- a/src/app/types/ProfileUser.ts +++ b/src/app/types/ProfileUser.ts @@ -1,4 +1,5 @@ import { ProfileUserActions } from 'app/actions'; +import { RouteComponentProps } from 'react-router-dom'; import { ActionType } from 'typesafe-actions'; export enum ProfileUserType { @@ -17,7 +18,9 @@ export interface EditProfileUserDetails { } const actions = { + getMatchStats: ProfileUserActions.getMatchStats, getUserDetails: ProfileUserActions.getUserDetails, + updateMatchStats: ProfileUserActions.updateMatchStats, updateProfileUserDetails: ProfileUserActions.updateProfileUserDetails, }; @@ -30,6 +33,22 @@ export interface ProfileUserStoreState { type: string; userType: ProfileUserType; username: string; + matchStats: ProfileMatchStats; +} + +export interface MatchStatsItem { + wins: number; + losses: number; + ties: number; +} + +export interface ProfileMatchStats { + auto: MatchStatsItem; + faced: MatchStatsItem; + initiated: MatchStatsItem; + lastMatchAt: string; + numMatchches: number; + userId: number; } export interface StateProps { @@ -38,9 +57,14 @@ export interface StateProps { export interface DispatchProps { updateProfileUserDetails: (updateProfileUserDetails: EditProfileUserDetails) => void; - getUserDetails: () => void; + getUserDetails: (username: string) => void; getMatchStats: (username: string) => void; } -export type Props = StateProps & DispatchProps; + +interface UrlMatchParams { + username: string; +} + +export type Props = StateProps & DispatchProps & RouteComponentProps; export type ProfileUserStoreAction = ActionType;