Implement DraftArea

This commit is contained in:
Chi Vinh Le
2018-02-01 17:29:53 +01:00
parent dc5a3e43a6
commit 34726e2c4e
8 changed files with 167 additions and 42 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ import pluginsConfig from 'pluginsConfig';
// TODO: move init code into `bootstrap` service after auth has been refactored.
function preInit({ store, pym, inIframe }) {
// TODO: This is popup specific code and needs to be refactored.
if (!inIframe()) {
if (!inIframe) {
store.dispatch(addExternalConfig({}));
store.dispatch(checkLogin());
return;
@@ -2,13 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'coral-ui';
import cn from 'classnames';
import Slot from 'coral-framework/components/Slot';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
import { name } from '../containers/CommentBox';
import styles from './CommentForm.css';
import t from 'coral-framework/services/i18n';
import DraftArea from '../containers/DraftArea';
/**
* Common UI for Creating or Editing a Comment
@@ -61,10 +61,6 @@ export class CommentForm extends React.Component {
};
}
onBodyChange = e => {
this.props.onBodyChange(e.target.value);
};
onClickSubmit = () => {
this.props.onSubmit();
};
@@ -107,37 +103,16 @@ export class CommentForm extends React.Component {
return (
<div>
<div className={`${name}-container`}>
<label
htmlFor={this.props.bodyInputId}
className="screen-reader-text"
aria-hidden={true}
>
{this.props.bodyLabel}
</label>
<textarea
className={`${name}-textarea`}
value={body}
placeholder={this.props.bodyPlaceholder}
id={this.props.bodyInputId}
onChange={this.onBodyChange}
rows={3}
disabled={disableTextArea}
/>
<Slot fill="commentInputArea" />
</div>
{this.props.charCountEnable && (
<div
className={`${name}-char-count ${
length > maxCharCount ? `${name}-char-max` : ''
}`}
>
{maxCharCount &&
`${maxCharCount - length} ${t(
'comment_box.characters_remaining'
)}`}
</div>
)}
<DraftArea
id={this.props.bodyInputId}
label={this.props.bodyLabel}
value={body}
placeholder={this.props.bodyPlaceholder}
onChange={this.props.onBodyChange}
disabled={disableTextArea}
charCountEnable={this.props.charCountEnable}
maxCharCount={this.props.maxCharCount}
/>
<div className={`${name}-button-container`}>
{this.props.buttonContainerStart}
{typeof this.props.onCancel === 'function' && (
@@ -0,0 +1,77 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import t from 'coral-framework/services/i18n';
import Slot from 'coral-framework/components/Slot';
// TODO: (kiwi) Need to adapt CSS classes post refactor to match the rest.
/**
* An enhanced textarea to make comment drafts.
*/
export default class DraftArea extends React.Component {
renderCharCount() {
const { value, maxCharCount } = this.props;
const className = cn('talk-plugin-commentbox-char-count', {
['talk-plugin-commentbox-char-max']: value.length > maxCharCount,
});
const remaining = maxCharCount - value.length;
return (
<div className={className}>
{remaining} {t('comment_box.characters_remaining')}
</div>
);
}
render() {
const {
value,
placeholder,
id,
disabled,
rows,
label,
charCountEnable,
maxCharCount,
onChange,
} = this.props;
return (
<div>
<div className={'talk-plugin-commentbox-container'}>
<label htmlFor={id} className="screen-reader-text" aria-hidden={true}>
{label}
</label>
<textarea
className={'talk-plugin-commentbox-textarea'}
value={value}
placeholder={placeholder}
id={id}
onChange={onChange}
rows={rows}
disabled={disabled}
/>
<Slot fill="commentInputArea" />
</div>
{charCountEnable && maxCharCount > 0 && this.renderCharCount()}
</div>
);
}
}
DraftArea.defaultProps = {
rows: 3,
};
DraftArea.propTypes = {
charCountEnable: PropTypes.bool,
maxCharCount: PropTypes.number,
id: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
label: PropTypes.string,
onChange: PropTypes.func,
disabled: PropTypes.bool,
rows: PropTypes.number,
};
@@ -21,6 +21,7 @@ export class EditableCommentContent extends React.Component {
// comment that is being edited
comment: PropTypes.shape({
id: PropTypes.string,
body: PropTypes.string,
editing: PropTypes.shape({
edited: PropTypes.bool,
@@ -120,10 +121,12 @@ export class EditableCommentContent extends React.Component {
};
render() {
const id = `edit-draft_${this.props.comment.id}`;
return (
<div className={styles.editCommentForm}>
<CommentForm
defaultValue={this.props.comment.body}
bodyInputId={id}
charCountEnable={this.props.charCountEnable}
maxCharCount={this.props.maxCharCount}
submitEnabled={this.isSubmitEnabled}
@@ -7,7 +7,8 @@ const name = 'talk-plugin-replies';
class ReplyBox extends Component {
componentDidMount() {
document.getElementById('replyText').focus();
// TODO: (kiwi) This does not follow best practices, better to move this logic into the component.
document.getElementById(`comment-draft_${this.props.parentId}`).focus();
}
cancelReply = () => {
@@ -54,6 +55,8 @@ ReplyBox.propTypes = {
notify: PropTypes.func.isRequired,
postComment: PropTypes.func.isRequired,
assetId: PropTypes.string.isRequired,
currentUser: PropTypes.object,
styles: PropTypes.object,
};
export default ReplyBox;
@@ -20,7 +20,6 @@ class CommentBox extends React.Component {
super(props);
this.state = {
username: '',
body: '',
loadingState: '',
@@ -129,7 +128,7 @@ class CommentBox extends React.Component {
};
render() {
const { isReply, maxCharCount } = this.props;
const { isReply, maxCharCount, assetId, parentId } = this.props;
let { onCancel } = this.props;
if (isReply && typeof onCancel !== 'function') {
@@ -139,6 +138,11 @@ class CommentBox extends React.Component {
onCancel = () => {};
}
// Generate id for the DraftArea.
const id = parentId
? `comment-draft_${parentId}`
: `comment-draft_${assetId}`;
return (
<div>
<CommentForm
@@ -147,7 +151,7 @@ class CommentBox extends React.Component {
maxCharCount={maxCharCount}
charCountEnable={this.props.charCountEnable}
bodyPlaceholder={t('comment.comment')}
bodyInputId={isReply ? 'replyText' : 'commentText'}
bodyInputId={id}
body={this.state.body}
buttonContainerStart={
<Slot
@@ -0,0 +1,63 @@
import React from 'react';
import PropTypes from 'prop-types';
import DraftArea from '../components/DraftArea';
const STORAGE_PATH = 'DraftArea';
/**
* An enhanced textarea to make comment drafts.
*/
export default class DraftAreaContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.initValue();
}
async initValue() {
const value = await this.context.pymSessionStorage.getItem(this.getPath());
if (value && this.props.onChange) {
this.props.onChange(value);
}
}
getPath = () => {
return `${STORAGE_PATH}_${this.props.id}`;
};
onChange = e => {
this.context.pymSessionStorage.setItem(this.getPath(), e.target.value);
this.props.onChange && this.props.onChange(e.target.value);
};
render() {
return (
<DraftArea
value={this.props.value}
placeholder={this.props.placeholder}
id={this.props.id}
onChange={this.onChange}
rows={this.props.rows}
disabled={this.props.disabled}
charCountEnable={this.props.charCountEnable}
maxCharCount={this.props.maxCharCount}
label={this.props.label}
/>
);
}
}
DraftAreaContainer.contextTypes = {
pymSessionStorage: PropTypes.object,
};
DraftAreaContainer.propTypes = {
charCountEnable: PropTypes.bool,
maxCharCount: PropTypes.number,
id: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
onChange: PropTypes.func,
disabled: PropTypes.bool,
rows: PropTypes.number,
label: PropTypes.string,
};
+1 -1
View File
@@ -80,7 +80,7 @@ export async function createContext({
: localStorage;
const pymSessionStorage = inIframe
? createPymStorage(pym, 'sessionStorage')
: localStorage;
: sessionStorage;
const history = createHistory(BASE_PATH);
const introspection = createIntrospection(introspectionData);
let store = null;