Extract providers for comment component
All checks were successful
Build And Publish / BuildAndPublish (push) Successful in 3m13s

This commit is contained in:
Ryan Freeman 2025-04-08 22:05:01 +01:00
parent 45141726dd
commit f2eecf06d3
5 changed files with 75 additions and 46 deletions

View File

@ -0,0 +1,24 @@
import {createContext, ReactNode, RefObject, useContext, useRef} from 'react'
type CommentFormContext = {
commentFormRef?: RefObject<HTMLTextAreaElement | null>
focusCommentForm: () => void
}
export const CommentFormContext = createContext<CommentFormContext | null>(null)
export const useCommentFormContext = () => useContext(CommentFormContext)
export default function CommentFormProvider({children}: { children: ReactNode }) {
const commentFormRef = useRef<HTMLTextAreaElement>(null)
const focusCommentForm = () => {
commentFormRef.current?.focus()
}
return (
<CommentFormContext.Provider value={{commentFormRef, focusCommentForm}}>
{children}
</CommentFormContext.Provider>
)
}

View File

@ -0,0 +1,19 @@
import {createContext, ReactNode, useContext, useState} from 'react'
import type {Comment} from '@/types'
type ReplyContext = {
replyTo: Comment | null
setReplyTo: (replyTo: Comment | null) => void
}
export const ReplyContext = createContext<ReplyContext | null>(null)
export const useReplyContext = () => useContext(ReplyContext)
export default function ReplyProvider({children}: { children: ReactNode }) {
const [replyTo, setReplyTo] = useState<Comment | null>(null)
return (
<ReplyContext.Provider value={{replyTo, setReplyTo}}>{children}</ReplyContext.Provider>
)
}

View File

@ -10,6 +10,8 @@ import {getAllArticles} from '@/lib/getAllArticles'
import {getComments} from '@/lib/getComments'
import {format} from 'date-fns'
import type {Comment} from '@/types'
type ArticleLayout = {
title: string
date: string

View File

@ -1,6 +1,6 @@
'use client'
import React, {createContext, ReactNode, RefObject, useActionState, useContext, useEffect, useRef, useState} from 'react'
import React, {ReactNode, useActionState, useEffect, useState} from 'react'
import {useSession} from 'next-auth/react'
import Image from 'next/image'
import clsx from 'clsx'
@ -9,27 +9,18 @@ import {Button} from '@/components/ui/Button'
import {GitHubIcon} from '@/components/icons/SocialIcons'
import {ArrowLeftIcon} from '@/components/icons/ArrowLeftIcon'
import {getShortDurationFromNow} from '@/lib/dateFns'
import ReplyProvider, {useReplyContext} from '@/app/context/ReplyProvider'
import CommentFormProvider, {useCommentFormContext} from '@/app/context/CommentFormProvider'
type Comment = {
id: number
content: string
created_at: string
parent_id: number | null
user: {
id: number
name: string
image: string
}
replies?: Comment[]
}
import type {Comment} from '@/types'
type ReplyButton = {
comment: Comment
}
Comments.ReplyButton = function ReplyButton({comment}: ReplyButton) {
const replyContext = useContext(ReplyContext)
const commentFormContext = useContext(CommentFormContext)
const replyContext = useReplyContext()
const commentFormContext = useCommentFormContext()
const {data: session} = useSession()
const handleReplyButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
@ -132,18 +123,13 @@ const initialState: InitialState = {
message: ''
}
const CommentFormContext = createContext<{ focusCommentForm: () => void } | null>(null)
type CommentsFormsProps = {
slug: string
commentFormRef?: RefObject<HTMLTextAreaElement | null>
}
Comments.Form = function Form({slug, commentFormRef}: CommentsFormsProps) {
Comments.Form = function Form({slug}: { slug: string }) {
const [parentId, setParentId] = useState<string | number | null>('')
const [state, formAction, pending] = useActionState(addComment, initialState)
const {data: session} = useSession()
const replyContext = useContext(ReplyContext)
const replyContext = useReplyContext()
const commentFormContext = useCommentFormContext()
const commentFormRef = commentFormContext?.commentFormRef
useEffect(() => {
if (replyContext?.replyTo?.parent_id !== null) {
@ -214,37 +200,22 @@ Comments.Form = function Form({slug, commentFormRef}: CommentsFormsProps) {
)
}
type ReplyContextType = {
replyTo: Comment | null
setReplyTo: (replyTo: Comment | null) => void
}
const ReplyContext = createContext<ReplyContextType | null>(null)
type CommentsProps = {
slug: string
comments?: Comment[]
comments?: any
}
export default function Comments({slug, comments}: CommentsProps) {
const [replyTo, setReplyTo] = useState<Comment | null>(null)
const commentFormRef = useRef<HTMLTextAreaElement>(null)
const focusCommentForm = () => {
commentFormRef.current?.focus()
}
return (
<ReplyContext.Provider value={{replyTo, setReplyTo}}>
<CommentFormContext.Provider value={{focusCommentForm}}>
<CommentFormProvider>
<ReplyProvider>
<div className="mt-24">
{comments &&
<Comments.List comments={comments}/>
}
<Comments.Form slug={slug} commentFormRef={commentFormRef}/>
<Comments.Form slug={slug}/>
</div>
</CommentFormContext.Provider>
</ReplyContext.Provider>
</ReplyProvider>
</CommentFormProvider>
)
}

View File

@ -23,3 +23,16 @@ export type Repo = {
color: string
}
}
export type Comment = {
id: number
content: string
created_at: string
parent_id: number | null
user: {
id: number
name: string
image: string
}
replies?: Comment[]
}