Skip to main content
Glama
Southclaws

Storyden

by Southclaws
useReplyBox.ts3.35 kB
"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { Account, DatagraphItemKind, Thread } from "src/api/openapi-schema"; import { handle } from "@/api/client"; import { useSession } from "@/auth"; import { sendBeacon } from "@/lib/beacon/beacon"; import { useThreadMutations } from "@/lib/thread/mutation"; import { useReplyContext } from "../ReplyContext"; export type Props = { initialSession?: Account; thread: Thread; }; type ReplyLocationState = { id: string; pageNumber: number; permalink: string; }; export const FormSchema = z.object({ body: z.string().min(1, "Please enter a message."), }); export type Form = z.infer<typeof FormSchema>; export function useReplyBox({ initialSession, thread }: Props) { const session = useSession(initialSession); const { replyTo, clearReplyTo } = useReplyContext(); const { createReply, revalidate } = useThreadMutations( thread, thread.replies.current_page, thread.replies.total_pages, ); const [resetKey, setResetKey] = useState(""); const [isEmpty, setEmpty] = useState(true); const [postedReply, setPostedReply] = useState<ReplyLocationState | null>( null, ); const form = useForm<Form>({ resolver: zodResolver(FormSchema) }); function handleEmptyStateChange(isEmpty: boolean) { setEmpty(isEmpty); } function handleReplyPostedAdmonitionClose() { setPostedReply(null); } function handleReplyNavigation() { setPostedReply(null); } const handleSubmit = form.handleSubmit(async (data: Form) => { await handle( async () => { const { id } = await createReply({ body: data.body, reply_to: replyTo?.reply.id, }); // Mark the thread as read after successfully replying to it try { sendBeacon(DatagraphItemKind.thread, thread.id); } catch (error) { console.warn("failed to send beacon:", error); } // This is a little hack tbh, essentially if this prop for the // ContentComposer component changes, its value is reset. Could have // done it with a hook but... meh this is simpler (albeit not idiomatic) setResetKey(new Date().toISOString()); form.reset(); setEmpty(true); clearReplyTo(); // If we are not on the last page, we need to inform the user that their // reply is on a different page and provide them a link to navigate. const currentPage = thread.replies.current_page; const totalPages = thread.replies.total_pages; const isLastPage = !currentPage || !totalPages || currentPage === totalPages; if (!isLastPage && totalPages) { setPostedReply({ id, pageNumber: totalPages, permalink: `/t/${thread.slug}?page=${totalPages}#${id}`, }); } }, { cleanup: async () => await revalidate(), }, ); }); return { isLoggedIn: !!session, isEmpty, isLoading: form.formState.isSubmitting, resetKey, postedReply, form, handlers: { handleSubmit, handleEmptyStateChange, handleReplyPostedAdmonitionClose, handleReplyNavigation, }, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server