API & Client: Profile picture
This commit is contained in:
@ -11,6 +11,10 @@ function AuthErrors(messages) {
|
||||
return { type: 'AUTH_ERRORS', messages }
|
||||
}
|
||||
|
||||
function PictureError(message) {
|
||||
return { type: 'PICTURE_ERROR', message }
|
||||
}
|
||||
|
||||
function ProfileSuccess(message) {
|
||||
return { type: 'PROFILE_SUCCESS', message }
|
||||
}
|
||||
@ -151,7 +155,7 @@ export function handleProfileFormSubmit(event) {
|
||||
event.preventDefault()
|
||||
return (dispatch, getState) => {
|
||||
const state = getState()
|
||||
if (state.formProfile.formProfile.password !==
|
||||
if (!state.formProfile.formProfile.password ===
|
||||
state.formProfile.formProfile.passwordConf) {
|
||||
dispatch(PwdError('Password and password confirmation don\'t match.'))
|
||||
} else {
|
||||
@ -172,3 +176,41 @@ export function handleProfileFormSubmit(event) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function uploadPicture (event) {
|
||||
event.preventDefault()
|
||||
const form = new FormData()
|
||||
form.append('file', event.target.picture.files[0])
|
||||
event.target.reset()
|
||||
return function(dispatch) {
|
||||
return mpwoApi
|
||||
.updatePicture(form)
|
||||
.then(ret => {
|
||||
if (ret.status === 'success') {
|
||||
getProfile(dispatch)
|
||||
} else {
|
||||
dispatch(PictureError(ret.message))
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
throw error
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function deletePicture() {
|
||||
return function(dispatch) {
|
||||
return mpwoApi
|
||||
.deletePicture()
|
||||
.then(ret => {
|
||||
if (ret.status === 'success') {
|
||||
getProfile(dispatch)
|
||||
} else {
|
||||
dispatch(PictureError(ret.message))
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
throw error
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,18 @@
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.App-nav-profile-img {
|
||||
max-width: 35px;
|
||||
max-height: 35px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.App-profile-img-small {
|
||||
max-width: 150px;
|
||||
max-height: 150px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
|
@ -2,6 +2,9 @@ import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import mpwoApi from '../../mpwoApi'
|
||||
|
||||
|
||||
function NavBar (props) {
|
||||
return (
|
||||
<header>
|
||||
@ -56,6 +59,14 @@ function NavBar (props) {
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.user.picture === true && (
|
||||
<img
|
||||
alt="Profile"
|
||||
src={`${mpwoApi.getApiUrl()}users/${props.user.id}/picture` +
|
||||
`?${Date.now()}`}
|
||||
className="img-fluid App-nav-profile-img"
|
||||
/>
|
||||
)}
|
||||
{props.user.isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
|
@ -3,12 +3,18 @@ import { Helmet } from 'react-helmet'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
function Profile ({ user }) {
|
||||
import mpwoApi from '../../mpwoApi'
|
||||
import { deletePicture, uploadPicture } from '../../actions'
|
||||
|
||||
function Profile ({ message, onDeletePicture, onUploadPicture, user }) {
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>mpwo - {user.username} - Profile</title>
|
||||
</Helmet>
|
||||
{ message !== '' && (
|
||||
<code>{message}</code>
|
||||
)}
|
||||
<div className="container">
|
||||
<h1 className="page-title">Profile</h1>
|
||||
<div className="row">
|
||||
@ -35,6 +41,38 @@ function Profile ({ user }) {
|
||||
<p>Location : {user.location}</p>
|
||||
<p>Bio : {user.bio}</p>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
{ user.picture === true && (
|
||||
<div>
|
||||
<img
|
||||
alt="Profile"
|
||||
src={`${mpwoApi.getApiUrl()}users/${user.id}/picture` +
|
||||
`?${Date.now()}`}
|
||||
className="img-fluid App-profile-img-small"
|
||||
/>
|
||||
<br />
|
||||
<button
|
||||
type="submit"
|
||||
onClick={() => onDeletePicture()}
|
||||
>
|
||||
Delete picture
|
||||
</button>
|
||||
<br /><br />
|
||||
</div>
|
||||
)}
|
||||
<form
|
||||
encType="multipart/form-data"
|
||||
onSubmit={event => onUploadPicture(event)}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
name="picture"
|
||||
accept=".png,.jpg,.gif"
|
||||
/>
|
||||
<br />
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,6 +93,15 @@ function Profile ({ user }) {
|
||||
|
||||
export default connect(
|
||||
state => ({
|
||||
message: state.message,
|
||||
user: state.user,
|
||||
}),
|
||||
dispatch => ({
|
||||
onDeletePicture: () => {
|
||||
dispatch(deletePicture())
|
||||
},
|
||||
onUploadPicture: event => {
|
||||
dispatch(uploadPicture(event))
|
||||
},
|
||||
})
|
||||
)(Profile)
|
||||
|
@ -67,4 +67,30 @@ export default class MpwoApi {
|
||||
.then(response => response.json())
|
||||
.catch(error => error)
|
||||
}
|
||||
static updatePicture(form) {
|
||||
const request = new Request(`${apiUrl}auth/picture`, {
|
||||
method: 'POST',
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${window.localStorage.getItem('authToken')}`,
|
||||
}),
|
||||
body: form,
|
||||
})
|
||||
return fetch(request)
|
||||
.then(response => response.json())
|
||||
.catch(error => error)
|
||||
}
|
||||
static deletePicture() {
|
||||
const request = new Request(`${apiUrl}auth/picture`, {
|
||||
method: 'DELETE',
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${window.localStorage.getItem('authToken')}`,
|
||||
}),
|
||||
})
|
||||
return fetch(request)
|
||||
.then(response => response.json())
|
||||
.catch(error => error)
|
||||
}
|
||||
static getApiUrl() {
|
||||
return apiUrl
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ const message = (state = initial.message, action) => {
|
||||
case 'AUTH_ERROR':
|
||||
case 'PROFILE_ERROR':
|
||||
case 'PWD_ERROR':
|
||||
case 'PICTURE_ERROR':
|
||||
return action.message
|
||||
case 'LOGOUT':
|
||||
case 'PROFILE_SUCCESS':
|
||||
@ -103,6 +104,9 @@ const user = (state = initial.user, action) => {
|
||||
birthDate: action.message.data.birth_date
|
||||
? action.message.data.birth_date
|
||||
: '',
|
||||
picture: action.message.data.picture === true
|
||||
? action.message.data.picture
|
||||
: false,
|
||||
}
|
||||
default:
|
||||
return state
|
||||
|
@ -12,7 +12,8 @@ export default {
|
||||
lastName: '',
|
||||
bio: '',
|
||||
location: '',
|
||||
birthDate: ''
|
||||
birthDate: '',
|
||||
picture: false
|
||||
},
|
||||
formData: {
|
||||
formData: {
|
||||
@ -30,7 +31,7 @@ export default {
|
||||
location: '',
|
||||
birthDate: '',
|
||||
password: '',
|
||||
passwordConf: ''
|
||||
passwordConf: '',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
Reference in New Issue
Block a user