mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-28 13:22:39 +03:00
Wired up adding replies
This commit is contained in:
parent
2e58f65b24
commit
6a179b06c4
@ -28,6 +28,33 @@ async function addComment({state, api, data: comment}) {
|
||||
};
|
||||
}
|
||||
|
||||
async function addReply({state, api, data: {reply, parent}}) {
|
||||
let comment = reply;
|
||||
comment.parent_id = parent.id;
|
||||
|
||||
const data = await api.comments.add({comment});
|
||||
comment = data.comments[0];
|
||||
|
||||
// Temporary workaround for missing member relation (bug in API)
|
||||
comment = {
|
||||
...comment,
|
||||
member: state.member
|
||||
};
|
||||
|
||||
// Replace the comment in the state with the new one
|
||||
return {
|
||||
comments: state.comments.map((c) => {
|
||||
if (c.id === parent.id) {
|
||||
return {
|
||||
...parent,
|
||||
replies: [...parent.replies, comment]
|
||||
};
|
||||
}
|
||||
return c;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
async function hideComment({state, adminApi, data: comment}) {
|
||||
await adminApi.hideComment(comment.id);
|
||||
|
||||
@ -141,6 +168,7 @@ const Actions = {
|
||||
showComment,
|
||||
likeComment,
|
||||
unlikeComment,
|
||||
addReply,
|
||||
loadMoreComments
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,7 @@ const Comment = (props) => {
|
||||
</div>
|
||||
{isInReplyMode &&
|
||||
<div className={`ml-14 mt-8`}>
|
||||
<ReplyForm />
|
||||
<ReplyForm parent={comment} />
|
||||
</div>
|
||||
}
|
||||
{hasReplies &&
|
||||
|
@ -1,93 +1,94 @@
|
||||
import React from 'react';
|
||||
import React, {useState, useContext} from 'react';
|
||||
import AppContext from '../AppContext';
|
||||
import Avatar from './Avatar';
|
||||
|
||||
class ReplyForm extends React.Component {
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
message: '',
|
||||
focused: false
|
||||
};
|
||||
|
||||
this.submitForm = this.submitForm.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
this.handleFocus = this.handleFocus.bind(this);
|
||||
}
|
||||
|
||||
getHTML() {
|
||||
const text = this.state.message;
|
||||
const ReplyForm = (props) => {
|
||||
const [message, setMessage] = useState('');
|
||||
const [focused, setFocused] = useState(false);
|
||||
const {member, postId, dispatchAction} = useContext(AppContext);
|
||||
|
||||
const getHTML = () => {
|
||||
// Convert newlines to <br> for now (until we add a real editor)
|
||||
return text.replace('\n', '<br>');
|
||||
}
|
||||
return message.replace('\n', '<br>');
|
||||
};
|
||||
|
||||
async submitForm(event) {
|
||||
const submitForm = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
// TODO: Add logic to make this work
|
||||
|
||||
// Clear message on success
|
||||
this.setState({
|
||||
message: '',
|
||||
focused: false
|
||||
});
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({message: event.target.value});
|
||||
}
|
||||
|
||||
handleBlur(event) {
|
||||
if (this.state.message === '') {
|
||||
this.setState({focused: false});
|
||||
if (message.length === 0) {
|
||||
// alert('Please enter a message'); TODO: Check, but don't think we really need this
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
handleFocus(event) {
|
||||
this.setState({focused: true});
|
||||
}
|
||||
try {
|
||||
// Send comment to server
|
||||
await dispatchAction('addReply', {
|
||||
parent: props.parent,
|
||||
reply: {
|
||||
post_id: postId,
|
||||
status: 'published',
|
||||
html: getHTML()
|
||||
}
|
||||
});
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={this.submitForm} className="comment-form">
|
||||
<div className="w-full">
|
||||
<div className="flex mb-4 space-x-4 justify-start items-center">
|
||||
<Avatar />
|
||||
<div>
|
||||
<h4 className="text-lg font-sans font-bold mb-1 tracking-tight dark:text-neutral-300">{this.context.member.name}</h4>
|
||||
<h6 className="text-[13px] text-neutral-400 font-sans">Now</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pr-3 font-sans leading-normal dark:text-neutral-300">
|
||||
<div className="relative w-full">
|
||||
<textarea
|
||||
className={`transition-[height] duration-150 w-full resize-none rounded-md border border-slate-200 p-3 font-sans mb-1 leading-normal focus:outline-0 dark:bg-[rgba(255,255,255,0.08)] dark:border-none dark:text-neutral-300 ${this.state.focused ? 'cursor-text h-40' : 'cursor-pointer overflow-hidden h-12 hover:border-slate-300'}`}
|
||||
value={this.state.message}
|
||||
onChange={this.handleChange}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
placeholder={this.state.focused ? '' : 'Reply to this comment'}
|
||||
/>
|
||||
<button
|
||||
className={`transition-[opacity] duration-150 rounded-md border py-2 px-3 font-sans text-sm text-center bg-black font-semibold text-white dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${this.state.focused ? 'opacity-100' : 'opacity-0'}`}
|
||||
type="submit">
|
||||
Add your reply
|
||||
</button>
|
||||
<button
|
||||
className={`transition-[opacity] duration-100 absolute top-2 right-2 rounded-md border py-1 px-2 font-sans text-sm text-center bg-black font-semibold text-white pointer-events-none dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${this.state.focused ? 'opacity-0' : 'opacity-100'}`}
|
||||
disabled="true">
|
||||
Reply
|
||||
</button>
|
||||
</div>
|
||||
// Clear message on success
|
||||
setMessage('');
|
||||
setFocused(false);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setMessage(event.target.value);
|
||||
};
|
||||
|
||||
const handleBlur = (event) => {
|
||||
if (message === '') {
|
||||
setFocused(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = (event) => {
|
||||
setFocused(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={submitForm} className="comment-form">
|
||||
<div className="w-full">
|
||||
<div className="flex mb-4 space-x-4 justify-start items-center">
|
||||
<Avatar />
|
||||
<div>
|
||||
<h4 className="text-lg font-sans font-bold mb-1 tracking-tight dark:text-neutral-300">{member.name}</h4>
|
||||
<h6 className="text-[13px] text-neutral-400 font-sans">Now</h6>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
<div className="pr-3 font-sans leading-normal dark:text-neutral-300">
|
||||
<div className="relative w-full">
|
||||
<textarea
|
||||
className={`transition-[height] duration-150 w-full resize-none rounded-md border border-slate-200 p-3 font-sans mb-1 leading-normal focus:outline-0 dark:bg-[rgba(255,255,255,0.08)] dark:border-none dark:text-neutral-300 ${focused ? 'cursor-text h-40' : 'cursor-pointer overflow-hidden h-12 hover:border-slate-300'}`}
|
||||
value={message}
|
||||
onChange={handleChange}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
placeholder={focused ? '' : 'Reply to this comment'}
|
||||
/>
|
||||
<button
|
||||
className={`transition-[opacity] duration-150 rounded-md border py-2 px-3 font-sans text-sm text-center bg-black font-semibold text-white dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${focused ? 'opacity-100' : 'opacity-0'}`}
|
||||
type="submit">
|
||||
Add your reply
|
||||
</button>
|
||||
<button
|
||||
className={`transition-[opacity] duration-100 absolute top-2 right-2 rounded-md border py-1 px-2 font-sans text-sm text-center bg-black font-semibold text-white pointer-events-none dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${focused ? 'opacity-0' : 'opacity-100'}`}
|
||||
disabled={true}>
|
||||
Reply
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReplyForm;
|
||||
|
Loading…
Reference in New Issue
Block a user