aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2021-12-17 23:29:10 +0100
committerArmand Philippot <git@armandphilippot.com>2021-12-17 23:48:06 +0100
commit50d37beeb51c95aaead8b3ef2c946189a066486e (patch)
tree61b812d884251767e3ffd4a99d76968d680f9bd0
parentefed6c0a820c5c47e097fa29455157bbd318ffca (diff)
chore: create mutation to add a new comment on posts
-rw-r--r--src/components/CommentForm/CommentForm.tsx53
-rw-r--r--src/components/Notice/Notice.module.scss28
-rw-r--r--src/components/Notice/Notice.tsx20
-rw-r--r--src/pages/article/[slug].tsx2
-rw-r--r--src/services/graphql/comments.ts68
-rw-r--r--src/services/graphql/post.ts1
-rw-r--r--src/ts/types/comments.ts22
7 files changed, 191 insertions, 3 deletions
diff --git a/src/components/CommentForm/CommentForm.tsx b/src/components/CommentForm/CommentForm.tsx
index be6f5a6..988468c 100644
--- a/src/components/CommentForm/CommentForm.tsx
+++ b/src/components/CommentForm/CommentForm.tsx
@@ -1,16 +1,62 @@
import { ButtonSubmit } from '@components/Buttons';
import { Form, FormItem, Input, TextArea } from '@components/Form';
+import Notice from '@components/Notice/Notice';
import { t } from '@lingui/macro';
+import { createComment } from '@services/graphql/comments';
import { useState } from 'react';
-const CommentForm = () => {
+const CommentForm = ({
+ articleId,
+ parentId = 0,
+}: {
+ articleId: number;
+ parentId?: number;
+}) => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [website, setWebsite] = useState('');
const [message, setMessage] = useState('');
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [isApproved, setIsApproved] = useState(false);
+
+ const resetForm = () => {
+ setName('');
+ setEmail('');
+ setWebsite('');
+ setMessage('');
+ };
+
+ const submitHandler = async (e: SubmitEvent) => {
+ e.preventDefault();
+
+ if (name && email && message && articleId) {
+ const createdComment = await createComment(
+ name,
+ email,
+ website,
+ message,
+ parentId,
+ articleId,
+ 'createComment'
+ );
+
+ if (createdComment.success) setIsSuccess(true);
+ if (isSuccess) {
+ resetForm();
+ if (createdComment.comment?.approved) setIsApproved(true);
+
+ setTimeout(() => {
+ setIsSuccess(false);
+ setIsApproved(false);
+ }, 8000);
+ }
+ } else {
+ setIsSuccess(false);
+ }
+ };
return (
- <Form>
+ <Form submitHandler={submitHandler}>
<FormItem>
<Input
id="commenter-name"
@@ -51,6 +97,9 @@ const CommentForm = () => {
/>
</FormItem>
<ButtonSubmit>{t`Send`}</ButtonSubmit>
+ {isSuccess && !isApproved && (
+ <Notice type="success">{t`Thanks for your comment! It is now awaiting moderation.`}</Notice>
+ )}
</Form>
);
};
diff --git a/src/components/Notice/Notice.module.scss b/src/components/Notice/Notice.module.scss
new file mode 100644
index 0000000..deae4e4
--- /dev/null
+++ b/src/components/Notice/Notice.module.scss
@@ -0,0 +1,28 @@
+@use "@styles/abstracts/functions" as fun;
+
+.message {
+ border: fun.convert-px(2) solid;
+ font-weight: bold;
+ margin: var(--spacing-sm) auto;
+ padding: var(--spacing-2xs) var(--spacing-xs);
+
+ &--error {
+ border-color: var(--color-error);
+ color: var(--color-error);
+ }
+
+ &--info {
+ border-color: var(--color-info);
+ color: var(--color-info);
+ }
+
+ &--success {
+ border-color: var(--color-success);
+ color: var(--color-success);
+ }
+
+ &--warning {
+ border-color: var(--color-warning);
+ color: var(--color-warning);
+ }
+}
diff --git a/src/components/Notice/Notice.tsx b/src/components/Notice/Notice.tsx
new file mode 100644
index 0000000..c941bf9
--- /dev/null
+++ b/src/components/Notice/Notice.tsx
@@ -0,0 +1,20 @@
+import { ReactNode } from 'react';
+import styles from './Notice.module.scss';
+
+type NoticeType = 'error' | 'info' | 'success' | 'warning';
+
+const Notice = ({
+ children,
+ type,
+}: {
+ children: ReactNode;
+ type: NoticeType;
+}) => {
+ return (
+ <div className={`${styles.message} ${styles[`message--${type}`]}`}>
+ {children}
+ </div>
+ );
+};
+
+export default Notice;
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index df5ae51..55753c3 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -47,7 +47,7 @@ const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
<h2>{t`Comments`}</h2>
<CommentsList comments={comments} />
<h2>{t`Leave a comment`}</h2>
- <CommentForm />
+ <CommentForm articleId={post.databaseId} />
</section>
</article>
</>
diff --git a/src/services/graphql/comments.ts b/src/services/graphql/comments.ts
new file mode 100644
index 0000000..b7a9ed2
--- /dev/null
+++ b/src/services/graphql/comments.ts
@@ -0,0 +1,68 @@
+import {
+ CreatedCommentResponse,
+ CreatedCommentReturn,
+} from '@ts/types/comments';
+import { gql } from 'graphql-request';
+import { getGraphQLClient } from './client';
+
+export const createComment: CreatedCommentReturn = async (
+ author: string,
+ authorEmail: string,
+ authorUrl: string,
+ content: string,
+ parent: number,
+ commentOn: number,
+ mutationId: string
+) => {
+ const client = getGraphQLClient();
+ const mutation = gql`
+ mutation CreateComment(
+ $author: String!
+ $authorEmail: String!
+ $authorUrl: String!
+ $content: String!
+ $parent: ID!
+ $commentOn: Int!
+ $mutationId: String!
+ ) {
+ createComment(
+ input: {
+ author: $author
+ authorEmail: $authorEmail
+ authorUrl: $authorUrl
+ content: $content
+ parent: $parent
+ commentOn: $commentOn
+ clientMutationId: $mutationId
+ }
+ ) {
+ clientMutationId
+ success
+ comment {
+ approved
+ }
+ }
+ }
+ `;
+
+ const variables = {
+ author,
+ authorEmail,
+ authorUrl,
+ content,
+ parent,
+ commentOn,
+ mutationId,
+ };
+
+ try {
+ const response: CreatedCommentResponse = await client.request(
+ mutation,
+ variables
+ );
+ return response.createComment;
+ } catch (error) {
+ console.error(error, undefined, 2);
+ throw new Error(`An uncaught exception has occurred: ${error}`);
+ }
+};
diff --git a/src/services/graphql/post.ts b/src/services/graphql/post.ts
index 245bf7a..08411bf 100644
--- a/src/services/graphql/post.ts
+++ b/src/services/graphql/post.ts
@@ -65,6 +65,7 @@ const fetchPostBySlug: FetchPostByReturn = async (slug: string) => {
afterMore
beforeMore
}
+ databaseId
date
featuredImage {
node {
diff --git a/src/ts/types/comments.ts b/src/ts/types/comments.ts
index 51852d0..a1bb120 100644
--- a/src/ts/types/comments.ts
+++ b/src/ts/types/comments.ts
@@ -26,3 +26,25 @@ export type RawComment = Omit<Comment, 'author'> & {
export type CommentsResponse = {
nodes: RawComment[];
};
+
+export type CreatedComment = {
+ clientMutationId: string;
+ success: boolean;
+ comment: null | {
+ approved: boolean;
+ };
+};
+
+export type CreatedCommentResponse = {
+ createComment: CreatedComment;
+};
+
+export type CreatedCommentReturn = (
+ author: string,
+ authorEmail: string,
+ authorUrl: string,
+ content: string,
+ parent: number,
+ commentOn: number,
+ mutationId: string
+) => Promise<CreatedComment>;