Initial draft of comments

This commit is contained in:
Hollgy 2024-03-06 00:48:19 +01:00
parent 5916a21bd5
commit edb7ef2fc4
5 changed files with 164 additions and 13 deletions

View file

@ -0,0 +1,47 @@
import { useNavigate } from "@solidjs/router";
import { For, JSXElement, Show, createSignal } from "solid-js";
import { CheckMark, loadSpinner } from "../Util/Icons";
import { PublicComment, getComments } from "../Util/api";
//exported into primary as a Route
export function Comment({ postId }: { postId: string }): JSXElement {
const [comments, setComments] = createSignal([] as PublicComment[]);
const [loading, setLoading] = createSignal(true);
getComments(postId, 10, 0).then((comment) => {
setComments(comment);
setLoading(false);
});
return (
<Show when={!loading()} fallback={loadSpinner()}>
<For each={comments()}>
{(comment): JSXElement => <CommentSegment comment={comment} />}
</For>
</Show>
);
}
export function CommentSegment(props: { comment: PublicComment }): JSXElement {
const nav = useNavigate();
return (
<div class="card compact w-full flex-grow border-b-2 border-b-base-300 bg-base-200 text-base-content transition-all hover:bg-base-300">
<div class="card-body">
<p class="break-words text-base-content md:px-6 md:pt-2">
{props.comment?.content}
</p>
<div class="card-actions justify-end">
<button
onClick={(): void =>
nav("/comments?post_id" + props.comment?.parent_comment_id)
}
class="btn btn-xs"
>
<CheckMark />
</button>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,21 @@
import {
For,
JSXElement,
Show,
createResource,
createSignal,
useContext,
} from "solid-js";
import { getComments } from "../Util/api";
import { CommentSegment } from "./Comment";
export function CommentSection({ postId }: { postId: string }): JSXElement {
const [comments] = createResource(postId, () => getComments(postId, 0, 10));
return (
<For each={comments()!}>
{(comment) => <CommentSegment comment={comment} />}
</For>
);
}

View file

@ -0,0 +1,69 @@
import { useNavigate } from "@solidjs/router";
import { JSXElement, Show, createSignal, onMount, useContext } from "solid-js";
import { LoginContext } from "../Context/GlobalState";
import { NewComment, createComment } from "../Util/api";
export function NewCommentInputArea({
parentPostId,
}: {
parentPostId: number;
}): JSXElement {
const [content, setContent] = createSignal("");
const [waiting, setWaiting] = createSignal(false);
// We assumte this context is always available
const login_ctx = useContext(LoginContext)!;
const nav = useNavigate();
const sendComment = (): void => {
setWaiting(true);
const response = createComment({
content: content(),
user_token: login_ctx.token(),
parent_post_id: parentPostId,
} as NewComment);
if (response) {
response.then(() => {
setWaiting(false);
setContent("");
nav("/");
});
}
};
// Bail out if not logged in
onMount(() => {
if (!login_ctx.loggedIn()) nav("/");
});
return (
<Show
when={!waiting()}
fallback={<span class="loading loading-spinner loading-lg self-center" />}
>
<div class="flex w-full flex-col space-y-2">
<textarea
class="textarea textarea-bordered h-32"
placeholder="Reply to post..."
maxLength={500}
onInput={(input): void => {
setContent(input.target.value);
}}
/>
<button
class={
"btn btn-primary btn-sm self-end" +
(content() == "" ? " btn-disabled" : "")
}
onClick={sendComment}
>
Submit
</button>
</div>
</Show>
);
}

View file

@ -1,29 +1,22 @@
import { useParams } from "@solidjs/router";
import { For, JSXElement, Show, Suspense, createResource } from "solid-js";
import { JSXElement, Show, Suspense, createResource } from "solid-js";
import { loadSpinner } from "../Util/Icons";
import { getComments, getPost } from "../Util/api";
import { getPost } from "../Util/api";
import { CommentSection } from "./CommentSection";
import { PostSegment } from "./Posts";
import { NewCommentInputArea } from "./NewComment";
export function SinglePost(): JSXElement {
const params = useParams();
const [post] = createResource(params.postid, getPost);
const [comments] = createResource(params.postid, () =>
getComments(params.postid, 0, 10)
);
return (
<Suspense fallback={loadSpinner()}>
<Show when={post()}>
<PostSegment post={post()!} />
<For each={comments()!}>
{(comment) => (
// TODO: This should be a separate component
<div class="comment">
<p>{comment.content}</p>
</div>
)}
</For>
<NewCommentInputArea parentPostId={parseInt(params.postid)}/>
<CommentSection postId={params.post_id} />
</Show>
</Suspense>
);

View file

@ -16,6 +16,17 @@ export interface Post extends NewPost {
votes: Votes;
}
export interface NewComment {
content: string;
user_token: string;
parent_post_id: number;
}
export interface Comment extends NewComment {
content: string;
token: string;
}
// This is what the login and registration responses look like
export interface AuthResponse {
username: string;
@ -56,6 +67,16 @@ export async function createPost(post: NewPost): Promise<void> {
});
}
export async function createComment(comment: NewComment): Promise<void> {
await fetch("/api/comments", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(comment),
});
}
// Gets the comments for a specific post
export async function getComments(
postId: string,