API & Client : add a link to display user detail in admin - #15
This commit is contained in:
parent
f1257f98a4
commit
33ed19a7e7
@ -230,30 +230,32 @@
|
|||||||
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
|
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
|
||||||
|
|
||||||
<span class="p">{</span>
|
<span class="p">{</span>
|
||||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
<span class="nt">"data"</span><span class="p">:</span> <span class="p">[</span>
|
||||||
<span class="nt">"admin"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
<span class="p">{</span>
|
||||||
<span class="nt">"bio"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
<span class="nt">"admin"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||||
<span class="nt">"birth_date"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
<span class="nt">"bio"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||||
<span class="nt">"created_at"</span><span class="p">:</span> <span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span>
|
<span class="nt">"birth_date"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||||
<span class="nt">"email"</span><span class="p">:</span> <span class="s2">"admin@example.com"</span><span class="p">,</span>
|
<span class="nt">"created_at"</span><span class="p">:</span> <span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span>
|
||||||
<span class="nt">"first_name"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
<span class="nt">"email"</span><span class="p">:</span> <span class="s2">"admin@example.com"</span><span class="p">,</span>
|
||||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
<span class="nt">"first_name"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||||
<span class="nt">"language"</span><span class="p">:</span> <span class="s2">"en"</span><span class="p">,</span>
|
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||||
<span class="nt">"last_name"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
<span class="nt">"language"</span><span class="p">:</span> <span class="s2">"en"</span><span class="p">,</span>
|
||||||
<span class="nt">"location"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
<span class="nt">"last_name"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||||
<span class="nt">"nb_activities"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
<span class="nt">"location"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||||
<span class="nt">"nb_sports"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
|
<span class="nt">"nb_activities"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
||||||
<span class="nt">"picture"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
<span class="nt">"nb_sports"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
|
||||||
<span class="nt">"sports_list"</span><span class="p">:</span> <span class="p">[</span>
|
<span class="nt">"picture"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||||
<span class="mi">1</span><span class="p">,</span>
|
<span class="nt">"sports_list"</span><span class="p">:</span> <span class="p">[</span>
|
||||||
<span class="mi">4</span><span class="p">,</span>
|
<span class="mi">1</span><span class="p">,</span>
|
||||||
<span class="mi">6</span>
|
<span class="mi">4</span><span class="p">,</span>
|
||||||
<span class="p">],</span>
|
<span class="mi">6</span>
|
||||||
<span class="nt">"timezone"</span><span class="p">:</span> <span class="s2">"Europe/Paris"</span><span class="p">,</span>
|
<span class="p">],</span>
|
||||||
<span class="nt">"total_distance"</span><span class="p">:</span> <span class="mf">67.895</span><span class="p">,</span>
|
<span class="nt">"timezone"</span><span class="p">:</span> <span class="s2">"Europe/Paris"</span><span class="p">,</span>
|
||||||
<span class="nt">"total_duration"</span><span class="p">:</span> <span class="s2">"6:50:27"</span><span class="p">,</span>
|
<span class="nt">"total_distance"</span><span class="p">:</span> <span class="mf">67.895</span><span class="p">,</span>
|
||||||
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"admin"</span>
|
<span class="nt">"total_duration"</span><span class="p">:</span> <span class="s2">"6:50:27"</span><span class="p">,</span>
|
||||||
<span class="p">},</span>
|
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"admin"</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
<span class="p">],</span>
|
||||||
<span class="nt">"status"</span><span class="p">:</span> <span class="s2">"success"</span>
|
<span class="nt">"status"</span><span class="p">:</span> <span class="s2">"success"</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
@ -33,24 +33,26 @@ def test_single_user(app, user_1):
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert data['status'] == 'success'
|
assert data['status'] == 'success'
|
||||||
assert data['data'] is not None
|
assert len(data['data']['users']) == 1
|
||||||
assert data['data']['username'] == 'test'
|
|
||||||
assert data['data']['email'] == 'test@test.com'
|
user = data['data']['users'][0]
|
||||||
assert data['data']['created_at']
|
assert user['username'] == 'test'
|
||||||
assert not data['data']['admin']
|
assert user['email'] == 'test@test.com'
|
||||||
assert data['data']['first_name'] is None
|
assert user['created_at']
|
||||||
assert data['data']['last_name'] is None
|
assert not user['admin']
|
||||||
assert data['data']['birth_date'] is None
|
assert user['first_name'] is None
|
||||||
assert data['data']['bio'] is None
|
assert user['last_name'] is None
|
||||||
assert data['data']['location'] is None
|
assert user['birth_date'] is None
|
||||||
assert data['data']['timezone'] is None
|
assert user['bio'] is None
|
||||||
assert data['data']['weekm'] is False
|
assert user['location'] is None
|
||||||
assert data['data']['language'] is None
|
assert user['timezone'] is None
|
||||||
assert data['data']['nb_activities'] == 0
|
assert user['weekm'] is False
|
||||||
assert data['data']['nb_sports'] == 0
|
assert user['language'] is None
|
||||||
assert data['data']['sports_list'] == []
|
assert user['nb_activities'] == 0
|
||||||
assert data['data']['total_distance'] == 0
|
assert user['nb_sports'] == 0
|
||||||
assert data['data']['total_duration'] == '0:00:00'
|
assert user['sports_list'] == []
|
||||||
|
assert user['total_distance'] == 0
|
||||||
|
assert user['total_duration'] == '0:00:00'
|
||||||
|
|
||||||
|
|
||||||
def test_single_user_with_activities(
|
def test_single_user_with_activities(
|
||||||
@ -80,24 +82,26 @@ def test_single_user_with_activities(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert data['status'] == 'success'
|
assert data['status'] == 'success'
|
||||||
assert data['data'] is not None
|
assert len(data['data']['users']) == 1
|
||||||
assert data['data']['username'] == 'test'
|
|
||||||
assert data['data']['email'] == 'test@test.com'
|
user = data['data']['users'][0]
|
||||||
assert data['data']['created_at']
|
assert user['username'] == 'test'
|
||||||
assert not data['data']['admin']
|
assert user['email'] == 'test@test.com'
|
||||||
assert data['data']['first_name'] is None
|
assert user['created_at']
|
||||||
assert data['data']['last_name'] is None
|
assert not user['admin']
|
||||||
assert data['data']['birth_date'] is None
|
assert user['first_name'] is None
|
||||||
assert data['data']['bio'] is None
|
assert user['last_name'] is None
|
||||||
assert data['data']['location'] is None
|
assert user['birth_date'] is None
|
||||||
assert data['data']['timezone'] is None
|
assert user['bio'] is None
|
||||||
assert data['data']['weekm'] is False
|
assert user['location'] is None
|
||||||
assert data['data']['language'] is None
|
assert user['timezone'] is None
|
||||||
assert data['data']['nb_activities'] == 2
|
assert user['weekm'] is False
|
||||||
assert data['data']['nb_sports'] == 2
|
assert user['language'] is None
|
||||||
assert data['data']['sports_list'] == [1, 2]
|
assert user['nb_activities'] == 2
|
||||||
assert data['data']['total_distance'] == 22
|
assert user['nb_sports'] == 2
|
||||||
assert data['data']['total_duration'] == '1:57:04'
|
assert user['sports_list'] == [1, 2]
|
||||||
|
assert user['total_distance'] == 22
|
||||||
|
assert user['total_duration'] == '1:57:04'
|
||||||
|
|
||||||
|
|
||||||
def test_single_user_no_id(app, user_1):
|
def test_single_user_no_id(app, user_1):
|
||||||
|
@ -119,30 +119,32 @@ def get_single_user(auth_user_id, user_id):
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"data": {
|
"data": [
|
||||||
"admin": true,
|
{
|
||||||
"bio": null,
|
"admin": true,
|
||||||
"birth_date": null,
|
"bio": null,
|
||||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
"birth_date": null,
|
||||||
"email": "admin@example.com",
|
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||||
"first_name": null,
|
"email": "admin@example.com",
|
||||||
"id": 1,
|
"first_name": null,
|
||||||
"language": "en",
|
"id": 1,
|
||||||
"last_name": null,
|
"language": "en",
|
||||||
"location": null,
|
"last_name": null,
|
||||||
"nb_activities": 6,
|
"location": null,
|
||||||
"nb_sports": 3,
|
"nb_activities": 6,
|
||||||
"picture": false,
|
"nb_sports": 3,
|
||||||
"sports_list": [
|
"picture": false,
|
||||||
1,
|
"sports_list": [
|
||||||
4,
|
1,
|
||||||
6
|
4,
|
||||||
],
|
6
|
||||||
"timezone": "Europe/Paris",
|
],
|
||||||
"total_distance": 67.895,
|
"timezone": "Europe/Paris",
|
||||||
"total_duration": "6:50:27",
|
"total_distance": 67.895,
|
||||||
"username": "admin"
|
"total_duration": "6:50:27",
|
||||||
},
|
"username": "admin"
|
||||||
|
}
|
||||||
|
],
|
||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +168,10 @@ def get_single_user(auth_user_id, user_id):
|
|||||||
if not user:
|
if not user:
|
||||||
return jsonify(response_object), 404
|
return jsonify(response_object), 404
|
||||||
else:
|
else:
|
||||||
response_object = {'status': 'success', 'data': user.serialize()}
|
response_object = {
|
||||||
|
'status': 'success',
|
||||||
|
'data': {'users': [user.serialize()]},
|
||||||
|
}
|
||||||
return jsonify(response_object), 200
|
return jsonify(response_object), 200
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return jsonify(response_object), 404
|
return jsonify(response_object), 404
|
||||||
|
@ -2,6 +2,7 @@ import { format } from 'date-fns'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
import Message from '../../Common/Message'
|
import Message from '../../Common/Message'
|
||||||
import { history } from '../../../index'
|
import { history } from '../../../index'
|
||||||
@ -39,7 +40,9 @@ class AdminUsers extends React.Component {
|
|||||||
{users.map(user => (
|
{users.map(user => (
|
||||||
<tr key={user.id}>
|
<tr key={user.id}>
|
||||||
<th scope="row">{user.id}</th>
|
<th scope="row">{user.id}</th>
|
||||||
<td>{user.username}</td>
|
<td>
|
||||||
|
<Link to={`/users/${user.id}`}>{user.username}</Link>
|
||||||
|
</td>
|
||||||
<td>{user.email}</td>
|
<td>{user.email}</td>
|
||||||
<td>
|
<td>
|
||||||
{format(
|
{format(
|
||||||
|
@ -6,15 +6,16 @@ import './App.css'
|
|||||||
import Admin from './Admin'
|
import Admin from './Admin'
|
||||||
import Activity from './Activity'
|
import Activity from './Activity'
|
||||||
import Activities from './Activities'
|
import Activities from './Activities'
|
||||||
|
import CurrentUserProfile from './User/CurrentUserProfile'
|
||||||
import Dashboard from './Dashboard'
|
import Dashboard from './Dashboard'
|
||||||
import Footer from './Footer'
|
import Footer from './Footer'
|
||||||
import Logout from './User/Logout'
|
import Logout from './User/Logout'
|
||||||
import NavBar from './NavBar'
|
import NavBar from './NavBar'
|
||||||
import NotFound from './Others/NotFound'
|
import NotFound from './Others/NotFound'
|
||||||
import Profile from './User/Profile'
|
|
||||||
import ProfileEdit from './User/ProfileEdit'
|
import ProfileEdit from './User/ProfileEdit'
|
||||||
import Statistics from './Statistics'
|
import Statistics from './Statistics'
|
||||||
import UserForm from './User/UserForm'
|
import UserForm from './User/UserForm'
|
||||||
|
import UserProfile from './User/UserProfile'
|
||||||
import { getAppData } from '../actions/application'
|
import { getAppData } from '../actions/application'
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
@ -44,9 +45,10 @@ class App extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<Route exact path="/logout" component={Logout} />
|
<Route exact path="/logout" component={Logout} />
|
||||||
<Route exact path="/profile/edit" component={ProfileEdit} />
|
<Route exact path="/profile/edit" component={ProfileEdit} />
|
||||||
<Route exact path="/profile" component={Profile} />
|
<Route exact path="/profile" component={CurrentUserProfile} />
|
||||||
<Route exact path="/activities/history" component={Activities} />
|
<Route exact path="/activities/history" component={Activities} />
|
||||||
<Route exact path="/activities/statistics" component={Statistics} />
|
<Route exact path="/activities/statistics" component={Statistics} />
|
||||||
|
<Route exact path="/users/:userId" component={UserProfile} />
|
||||||
<Route path="/activities" component={Activity} />
|
<Route path="/activities" component={Activity} />
|
||||||
<Route path="/admin" component={Admin} />
|
<Route path="/admin" component={Admin} />
|
||||||
<Route component={NotFound} />
|
<Route component={NotFound} />
|
||||||
|
@ -4,10 +4,10 @@ import { connect } from 'react-redux'
|
|||||||
|
|
||||||
import ProfileDetail from './ProfileDetail'
|
import ProfileDetail from './ProfileDetail'
|
||||||
|
|
||||||
function Profile({ t, user }) {
|
function CurrentUserProfile({ t, user }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ProfileDetail t={t} user={user} />
|
<ProfileDetail editable t={t} user={user} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -15,5 +15,5 @@ function Profile({ t, user }) {
|
|||||||
export default withTranslation()(
|
export default withTranslation()(
|
||||||
connect(state => ({
|
connect(state => ({
|
||||||
user: state.user,
|
user: state.user,
|
||||||
}))(Profile)
|
}))(CurrentUserProfile)
|
||||||
)
|
)
|
@ -11,6 +11,7 @@ import { apiUrl, getFileSize } from '../../utils'
|
|||||||
|
|
||||||
function ProfileDetail({
|
function ProfileDetail({
|
||||||
appConfig,
|
appConfig,
|
||||||
|
editable,
|
||||||
message,
|
message,
|
||||||
onDeletePicture,
|
onDeletePicture,
|
||||||
onUploadPicture,
|
onUploadPicture,
|
||||||
@ -37,13 +38,15 @@ function ProfileDetail({
|
|||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-header userName">
|
<div className="card-header userName">
|
||||||
{user.username}{' '}
|
{user.username}{' '}
|
||||||
<Link
|
{editable && (
|
||||||
to={{
|
<Link
|
||||||
pathname: '/profile/edit',
|
to={{
|
||||||
}}
|
pathname: '/profile/edit',
|
||||||
>
|
}}
|
||||||
<i className="fa fa-pencil-square-o" aria-hidden="true" />
|
>
|
||||||
</Link>
|
<i className="fa fa-pencil-square-o" aria-hidden="true" />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
48
fittrackee_client/src/components/User/UserProfile.jsx
Normal file
48
fittrackee_client/src/components/User/UserProfile.jsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { withTranslation } from 'react-i18next'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
|
import ProfileDetail from './ProfileDetail'
|
||||||
|
import { getOrUpdateData } from '../../actions'
|
||||||
|
|
||||||
|
class UserProfile extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.loadUser(this.props.match.params.userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (prevProps.match.params.userId !== this.props.match.params.userId) {
|
||||||
|
this.props.loadUser(this.props.match.params.userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { t, currentUser, users } = this.props
|
||||||
|
const [user] = users
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{user && (
|
||||||
|
<ProfileDetail
|
||||||
|
editable={currentUser.id === user.id}
|
||||||
|
t={t}
|
||||||
|
user={user}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation()(
|
||||||
|
connect(
|
||||||
|
state => ({
|
||||||
|
currentUser: state.user,
|
||||||
|
users: state.users.data,
|
||||||
|
}),
|
||||||
|
dispatch => ({
|
||||||
|
loadUser: userId => {
|
||||||
|
dispatch(getOrUpdateData('getData', 'users', { id: userId }))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)(UserProfile)
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user