Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
Merge pull request #17 from Factual/feature/edit-kudo
Browse files Browse the repository at this point in the history
Feature/edit kudo #7
  • Loading branch information
leckman authored Aug 18, 2017
2 parents ef6a8a7 + c162249 commit 791fd6b
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/assets/stylesheets/kudos/components/_give-kudo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
display: block;
position: absolute;
width: 50%;
border: 1px solid #aaa;
border: 1px solid $dark-border-color;
border-top: none;
background-color: #fff;
border-bottom-left-radius: 4px;
Expand Down
24 changes: 24 additions & 0 deletions app/assets/stylesheets/kudos/components/_kudo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@
top: 1em;
}

.kudo__update {
position: absolute;
right: 1em;
text-align: right;
top: 4.25rem;
}

.kudo__edit-button {
@extend .btn;
height: 25px;
padding: 0;
text-align: center;
width: 50px;
}

.kudo__edit-button--save {
@extend .btn-primary;
}

.kudo__input {
border: 1px solid $dark-border-color;
border-radius: 0 0 4px 4px;
}

.kudo__receiver {
// text-align: center;
}
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/kudos/utils/_variables.scss
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
$spacer: 2rem;
$dark-border-color: #aaa;
14 changes: 12 additions & 2 deletions app/controllers/kudos_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def index
# :body [body of kudo]
def create
giver_id = current_user.id
receiver_email = kudo_params[:receiver_email]
receiver_email = params[:kudo][:receiver_email]

unless (receiver = User.find_by(email: receiver_email))
if !(/@factual.com$/ =~ receiver_email)
Expand All @@ -71,6 +71,16 @@ def create
end
end

def update
kudo = Kudo.find_by!(id: params[:kudo][:id], giver_id: current_user.id)

if kudo.update!(body: kudo_params[:body])
render json: { kudo: kudo }, status: :created
else
render json: { error: kudo.errors.messages.values.flatten.to_sentence }, status: :unprocessable_entity
end
end

private

def basic_user_info_by_id(id)
Expand All @@ -84,6 +94,6 @@ def basic_user_info_by_id(id)
end

def kudo_params
params.require(:kudo).permit(:body, :receiver_email)
params.require(:kudo).permit(:body)
end
end
37 changes: 37 additions & 0 deletions client/app/bundles/KudosApp/actions/actionCreators.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ const postedKudo = (receiverEmail, messageBody) => {
}
}

const updatedKudo = ( kudoId, newMessage ) => {
return {
type: actionTypes.UPDATED_KUDO,
kudoId,
newMessage
}
}

const serverReceivedKudo = (res) => {
const receiverId = res.data.kudo.receiver_id
const messageBody = res.data.kudo.body
Expand Down Expand Up @@ -95,6 +103,34 @@ const createKudo = (receiverEmail, messageBody, onSuccess = null, onFailure = nu
}
}

const editKudo = ( id, message, onSuccess = null, onFailure = null ) => {
return dispatch => {
dispatch(updatedKudo( id, message ))
dispatch(resetErrorMessage());

return request({
method: 'PATCH',
url: '/kudos/'+id,
responseType: 'json',
data: {
kudo: {
id: id,
body: message,
}
},
}).then(res => {
if (onSuccess) {
onSuccess(res);
}
}).catch(err => {
if (onFailure) {
onFailure(err);
}
dispatch(serverRejectedKudo(err))
})
}
}

const initialize = ({ id, name }) => {
return {
type: actionTypes.INITIALIZE,
Expand All @@ -106,6 +142,7 @@ const initialize = ({ id, name }) => {
export {
initialize,
createKudo,
editKudo,
addLike,
removeLike,
failedLike
Expand Down
61 changes: 55 additions & 6 deletions client/app/bundles/KudosApp/components/Kudo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ import _ from 'lodash';
import moment from 'moment';
import { grey400, lightBlue400 } from 'material-ui/styles/colors';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import Textarea from 'react-textarea-autosize';
import ThumbUp from 'material-ui/svg-icons/action/thumb-up';

export default class Kudo extends React.Component {

constructor(props, context) {
super(props, context);
_.bindAll(this, 'formatTimestamp', 'likedBySelf', 'formatLikeText');
_.bindAll(this, 'formatTimestamp', 'likedBySelf', 'formatLikeText', 'postedByActiveUser', 'makeEditable', 'setMessage', "update");
this.state = {
likeAction: this.props.likeKudo(this.props.id),
timestamp: this.formatTimestamp(this.props.kudo.given_at),
thumbColor: grey400,
likeText: this.formatLikeText(this.props.kudo.likes.length)
likeText: this.formatLikeText((this.props.kudo.likes ? this.props.kudo.likes.length : 0)),
body: this.props.kudo.body,
editing: false
};

if (this.likedBySelf(this.props.kudo.likes, this.props.giverId)) {
Expand All @@ -25,12 +28,11 @@ export default class Kudo extends React.Component {

formatTimestamp(t) {
let ts = moment(t);
console.log("Parsed Zone:", ts);
return `At ${ts.format('h:mm a')} on ${ts.format('MMM D, YYYY')}`
return `At ${ts.format('h:mm a')} on ${ts.format('MMM D, YYYY')}`;
}

formatLikeText(numLikes) {
if (numLikes == 0) {
if (numLikes === 0) {
return "";
}
return `${numLikes} ${numLikes === 1 ? 'person likes': 'people like'} this`;
Expand All @@ -49,6 +51,25 @@ export default class Kudo extends React.Component {
return match
}

postedByActiveUser() {
let user = this.props.giverId;
let poster = this.props.kudo.giver_id;
return (user === poster);
}

makeEditable(e) {
this.setState({editing: true});
}

setMessage(e) {
this.setState({body: e.target.value})
}

update(e) {
this.setState({editing: false});
this.props.updateKudo(this.props.kudo.id, this.state.body);
}

componentWillReceiveProps(props) {
if (this.props.kudo.likes != props.kudo.likes) {
this.setState({ likeText: this.formatLikeText(props.kudo.likes.length) });
Expand All @@ -61,21 +82,49 @@ export default class Kudo extends React.Component {
}

render() {

const Edit = () => <button
type='button'
className="kudo__edit-button"
onClick={this.makeEditable}>
Edit
</button>

const Save = () => <button
type='button'
className='kudo__edit-button kudo__edit-button--save'
onClick={this.update}>
Save
</button>

return <div className="kudo">
<h4 className="list-group-item-heading">Kudos, {this.props.kudo.receiver}!</h4>
<div className="kudo__receiver">
<img src={this.props.kudo.receiver_avatar} alt={this.props.kudo.receiver} className="kudo__avatar" />
</div>
<div className="kudo__message">
<blockquote className="blockquote">
{this.props.kudo.body}
{this.state.editing ? (
<Textarea
className="kudo__input"
value={this.state.body}
onChange={this.setMessage}
/>
) : (
this.state.body
)}
<footer className="blockquote-footer">{this.props.kudo.giver}</footer>
</blockquote>
</div>
<FloatingActionButton onClick={this.state.likeAction} mini={true} backgroundColor={this.state.thumbColor}>
<ThumbUp/>
</FloatingActionButton>
<div>{this.state.likeText}</div>
{this.postedByActiveUser() ? (
<div className="kudo__update">
{this.state.editing ? <Save /> : <Edit />}
</div>
) : (null)}
<div className="kudo__timestamp">
{this.state.timestamp}
</div>
Expand Down
21 changes: 17 additions & 4 deletions client/app/bundles/KudosApp/components/KudosList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,21 @@ import injectTapEventPlugin from 'react-tap-event-plugin';

injectTapEventPlugin();

const List = ({ giverId, kudos, likeKudo, unlikeKudo }) => {
const List = ({ giverId, kudos, likeKudo, unlikeKudo, updateKudo }) => {
return <div className="kudos-list">
{ kudos.length > 0 ? kudos.map(kudo => <Kudo id={kudo.id} giverId={giverId} key={kudo.id} kudo={kudo} likeKudo={likeKudo} unlikeKudo={unlikeKudo}/>) : 'No kudos' }
{ kudos.length > 0 ? (
kudos.map(kudo => <
Kudo id={kudo.id}
giverId={giverId}
key={kudo.id}
kudo={kudo}
likeKudo={likeKudo}
unlikeKudo={unlikeKudo}
updateKudo={updateKudo}
/>)
) : (
'No kudos'
)}
</div>
}

Expand All @@ -25,7 +37,8 @@ export default class KudosList extends React.Component {
totalKudos: PropTypes.number.isRequired,
fetchPage: PropTypes.func.isRequired,
likeKudo: PropTypes.func.isRequired,
unlikeKudo: PropTypes.func.isRequired
unlikeKudo: PropTypes.func.isRequired,
updateKudo: PropTypes.func.isRequired
}

constructor(props, context) {
Expand Down Expand Up @@ -56,7 +69,7 @@ export default class KudosList extends React.Component {
render() {
return <div className="kudos-list__container">
<TabBarContainer />
<List giverId={this.props.id} kudos={this.props.kudos} likeKudo={this.props.likeKudo} unlikeKudo={this.props.unlikeKudo} />
<List giverId={this.props.id} kudos={this.props.kudos} likeKudo={this.props.likeKudo} unlikeKudo={this.props.unlikeKudo} updateKudo={this.props.updateKudo} />
{this.props.isFetchingKudos ? <Spinner /> : null}
</div>
}
Expand Down
1 change: 1 addition & 0 deletions client/app/bundles/KudosApp/constants/appConstants.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import mirrorCreator from 'mirror-creator';

const actionTypes = mirrorCreator([
'POSTED_KUDO',
'UPDATED_KUDO',
'INITIALIZE',
'SERVER_RECEIVED_KUDO',
'SERVER_REJECTED_KUDO',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import request from 'axios'
import { addLike, failedLike, removeLike } from '../actions/actionCreators';
import { bindActionCreators } from 'redux';
import { addLike, failedLike, removeLike, editKudo } from '../actions/actionCreators';
import { fetchPage } from '../actions/tabActions';
import KudosList from '../components/KudosList'
import _ from 'lodash'
Expand Down Expand Up @@ -39,6 +40,7 @@ function mergeProps(stateProps, { dispatch }, ownProps) {
return Object.assign({
likeKudo: thumbKudo(dispatch, true, id, name),
unlikeKudo: thumbKudo(dispatch, false, id, name),
updateKudo: bindActionCreators(editKudo, dispatch),
fetchPage: () => dispatch(fetchPage(currentTab, kudos.length))
}, ownProps, _.omit(stateProps, ['currentTab']))
}
Expand Down
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true
Rails.application.routes.draw do
resources :kudos, only: [:index, :create], constraints: { format: :json }, defaults: { format: :json }
resources :kudos, only: [:index, :create, :update], constraints: { format: :json }, defaults: { format: :json }

get 'kudos_app', to: 'kudos_app#index'
# Auth
Expand Down

0 comments on commit 791fd6b

Please sign in to comment.