2019-10-24 10:32:00 -07:00
|
|
|
import React from 'react';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { Icon, Button, Input, message } from 'antd';
|
|
|
|
import { AppState } from 'store/reducers';
|
|
|
|
import { proposalActions } from 'modules/proposals';
|
|
|
|
import { rfpActions } from 'modules/rfps';
|
2019-11-13 15:23:36 -08:00
|
|
|
import { Proposal } from 'types';
|
2019-10-24 10:32:00 -07:00
|
|
|
import { Comment, RFP } from 'types';
|
|
|
|
import { likeProposal, likeComment, likeRfp } from 'api/api';
|
|
|
|
import AuthButton from 'components/AuthButton';
|
|
|
|
import './index.less';
|
|
|
|
|
|
|
|
interface OwnProps {
|
2019-11-13 15:23:36 -08:00
|
|
|
proposal?: Proposal;
|
|
|
|
proposal_card?: boolean;
|
2019-10-24 10:32:00 -07:00
|
|
|
comment?: Comment;
|
|
|
|
rfp?: RFP;
|
2019-10-30 19:01:38 -07:00
|
|
|
style?: React.CSSProperties;
|
2019-10-24 10:32:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
interface StateProps {
|
|
|
|
authUser: AppState['auth']['user'];
|
|
|
|
}
|
|
|
|
|
|
|
|
interface DispatchProps {
|
|
|
|
fetchProposal: typeof proposalActions['fetchProposal'];
|
|
|
|
updateComment: typeof proposalActions['updateProposalComment'];
|
|
|
|
fetchRfp: typeof rfpActions['fetchRfp'];
|
|
|
|
}
|
|
|
|
|
|
|
|
type Props = OwnProps & StateProps & DispatchProps;
|
|
|
|
|
|
|
|
const STATE = {
|
|
|
|
loading: false,
|
|
|
|
};
|
|
|
|
type State = typeof STATE;
|
|
|
|
|
2019-11-13 15:23:36 -08:00
|
|
|
class Like extends React.Component<Props, State> {
|
2019-10-24 10:32:00 -07:00
|
|
|
state: State = { ...STATE };
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { likesCount, authedLiked } = this.deriveInfo();
|
2019-11-13 15:23:36 -08:00
|
|
|
const { proposal, rfp, comment, style, proposal_card } = this.props;
|
2019-10-24 10:32:00 -07:00
|
|
|
const { loading } = this.state;
|
2019-11-13 15:23:36 -08:00
|
|
|
const zoom = comment || proposal_card ? 0.8 : 1;
|
|
|
|
const shouldShowLikeText = (!!proposal && !proposal_card) || !!rfp;
|
|
|
|
|
|
|
|
// if like button is on a proposal card...
|
|
|
|
// 1) use regular button to prevent login redirect
|
|
|
|
const IconButton = proposal_card ? Button : AuthButton;
|
|
|
|
// 2) prevent mouseover effects
|
|
|
|
const pointerEvents = proposal_card ? 'none' : undefined;
|
|
|
|
// 3) make button click a noop
|
|
|
|
const handleIconButtonClick = proposal_card ? undefined : this.handleLike;
|
2019-10-24 10:32:00 -07:00
|
|
|
|
|
|
|
return (
|
2019-11-13 15:23:36 -08:00
|
|
|
<Input.Group className="Like" compact style={{ zoom, pointerEvents, ...style }}>
|
|
|
|
<IconButton onClick={handleIconButtonClick}>
|
2019-10-24 10:32:00 -07:00
|
|
|
<Icon
|
|
|
|
theme={authedLiked ? 'filled' : 'outlined'}
|
|
|
|
type={loading ? 'loading' : 'like'}
|
|
|
|
/>
|
|
|
|
{shouldShowLikeText && (
|
|
|
|
<span className="Like-label">{authedLiked ? ' Unlike' : ' Like'}</span>
|
|
|
|
)}
|
2019-11-13 15:23:36 -08:00
|
|
|
</IconButton>
|
2019-10-24 10:32:00 -07:00
|
|
|
<Button className="Like-count" disabled>
|
|
|
|
<span>{likesCount}</span>
|
|
|
|
</Button>
|
|
|
|
</Input.Group>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private deriveInfo = () => {
|
|
|
|
let authedLiked = false;
|
|
|
|
let likesCount = 0;
|
|
|
|
|
|
|
|
const { proposal, comment, rfp } = this.props;
|
|
|
|
|
|
|
|
if (comment) {
|
|
|
|
authedLiked = comment.authedLiked;
|
|
|
|
likesCount = comment.likesCount;
|
|
|
|
} else if (proposal) {
|
|
|
|
authedLiked = proposal.authedLiked;
|
|
|
|
likesCount = proposal.likesCount;
|
|
|
|
} else if (rfp) {
|
|
|
|
authedLiked = rfp.authedLiked;
|
|
|
|
likesCount = rfp.likesCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
authedLiked,
|
|
|
|
likesCount,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleLike = () => {
|
|
|
|
if (this.state.loading) return;
|
|
|
|
const { proposal, rfp, comment } = this.props;
|
|
|
|
|
|
|
|
if (proposal) {
|
|
|
|
return this.handleProposalLike();
|
|
|
|
}
|
|
|
|
if (comment) {
|
|
|
|
return this.handleCommentLike();
|
|
|
|
}
|
|
|
|
if (rfp) {
|
|
|
|
return this.handleRfpLike();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleProposalLike = async () => {
|
|
|
|
if (!this.props.proposal) return;
|
|
|
|
|
|
|
|
const {
|
|
|
|
proposal: { proposalId, authedLiked },
|
|
|
|
fetchProposal,
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
this.setState({ loading: true });
|
|
|
|
try {
|
|
|
|
await likeProposal(proposalId, !authedLiked);
|
|
|
|
await fetchProposal(proposalId);
|
|
|
|
message.success(<>Proposal {authedLiked ? 'unliked' : 'liked'}</>);
|
|
|
|
} catch (error) {
|
|
|
|
// tslint:disable:no-console
|
|
|
|
console.error('Like.handleProposalLike - unable to change like state', error);
|
|
|
|
message.error('Unable to like proposal');
|
|
|
|
}
|
|
|
|
this.setState({ loading: false });
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleCommentLike = async () => {
|
|
|
|
if (!this.props.comment) return;
|
|
|
|
|
|
|
|
const {
|
|
|
|
comment: { id, authedLiked },
|
|
|
|
updateComment,
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
this.setState({ loading: true });
|
|
|
|
try {
|
|
|
|
const updatedComment = await likeComment(id, !authedLiked);
|
|
|
|
updateComment(id, updatedComment);
|
|
|
|
message.success(<>Comment {authedLiked ? 'unliked' : 'liked'}</>);
|
|
|
|
} catch (error) {
|
|
|
|
// tslint:disable:no-console
|
|
|
|
console.error('Like.handleCommentLike - unable to change like state', error);
|
|
|
|
message.error('Unable to like comment');
|
|
|
|
}
|
|
|
|
this.setState({ loading: false });
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleRfpLike = async () => {
|
|
|
|
if (!this.props.rfp) return;
|
|
|
|
|
|
|
|
const {
|
|
|
|
rfp: { id, authedLiked },
|
|
|
|
fetchRfp,
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
this.setState({ loading: true });
|
|
|
|
try {
|
|
|
|
await likeRfp(id, !authedLiked);
|
|
|
|
await fetchRfp(id);
|
|
|
|
message.success(<>Request for proposal {authedLiked ? 'unliked' : 'liked'}</>);
|
|
|
|
} catch (error) {
|
|
|
|
// tslint:disable:no-console
|
|
|
|
console.error('Like.handleRfpLike - unable to change like state', error);
|
|
|
|
message.error('Unable to like rfp');
|
|
|
|
}
|
|
|
|
this.setState({ loading: false });
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const withConnect = connect<StateProps, DispatchProps, OwnProps, AppState>(
|
|
|
|
state => ({
|
|
|
|
authUser: state.auth.user,
|
|
|
|
}),
|
|
|
|
{
|
|
|
|
fetchProposal: proposalActions.fetchProposal,
|
|
|
|
updateComment: proposalActions.updateProposalComment,
|
|
|
|
fetchRfp: rfpActions.fetchRfp,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2019-11-13 15:23:36 -08:00
|
|
|
export default withConnect(Like);
|