dh_demo

DreamHanks demo project
git clone git://git.lair.cx/dh_demo
Log | Files | Refs | README

[id].tsx (3018B)


      1 import Title from '@/components/elements/Title'
      2 import Container from '@/components/layout/Container'
      3 import Hero from '@/components/layout/Hero'
      4 import Section from '@/components/layout/Section'
      5 import { Pagination } from '@/components/Pagination'
      6 import ThreadCommentView from '@/components/threads/ThreadCommentView'
      7 import ThreadCommentList from '@/components/threads/ThreadCommentList'
      8 import ThreadCommentWrite from '@/components/threads/ThreadCommentWrite'
      9 import useRefresh from '@/lib/hooks/use_refresh'
     10 import { withConnection } from '@/lib/model_helpers'
     11 import {
     12   getThreadAndFirstComment,
     13   listThreadComments,
     14   Thread,
     15   ThreadComment,
     16 } from '@/lib/models/thread'
     17 import { parseIntOrDefault } from '@/lib/utils/number'
     18 import { GetServerSideProps, GetServerSidePropsResult } from 'next'
     19 import { useRouter } from 'next/router'
     20 import { useMemo } from 'react'
     21 
     22 const PAGE_SIZE = 10
     23 
     24 export interface ThreadViewPageProps {
     25   page: number
     26   thread: Thread
     27   firstComment: ThreadComment
     28   comments: ThreadComment[]
     29 }
     30 
     31 function getIdFromQuery (query: any) {
     32   if (typeof query.id === 'string') {
     33     return parseInt(query.id)
     34   }
     35   return null
     36 }
     37 
     38 export const getServerSideProps: GetServerSideProps<ThreadViewPageProps> = async (context) => {
     39   const id = getIdFromQuery(context.query)
     40   if (id == null) {
     41     return {
     42       notFound: true,
     43     }
     44   }
     45 
     46   const page = Math.max(1, parseIntOrDefault(context.query.page, 1))
     47 
     48   return await withConnection(async (conn): Promise<GetServerSidePropsResult<ThreadViewPageProps>> => {
     49     const threadAndFirstComment = await getThreadAndFirstComment(conn, [id])
     50     if (threadAndFirstComment == null) {
     51       return {
     52         notFound: true,
     53       }
     54     }
     55 
     56     const [thread, firstComment] = threadAndFirstComment
     57     const comments = await listThreadComments(conn, [id, PAGE_SIZE, (page - 1) * PAGE_SIZE])
     58 
     59     return {
     60       props: {
     61         page,
     62         thread,
     63         firstComment,
     64         comments,
     65       },
     66     }
     67   })
     68 }
     69 
     70 export default function ThreadViewPage (props: ThreadViewPageProps) {
     71   const router = useRouter()
     72 
     73   const handleRefresh = async () => {
     74     await router.replace({
     75       pathname: router.pathname,
     76       query: {
     77         ...router.query,
     78         page: 1,
     79       }
     80     })
     81   }
     82 
     83   const idStartsFrom = useMemo(() => {
     84     return (props.thread.commentCount ?? 0) - (props.page - 1) * PAGE_SIZE
     85   }, [props.page])
     86 
     87   return (
     88     <>
     89       <Hero>
     90         <Title kind="headline">{props.thread.title}</Title>
     91       </Hero>
     92 
     93       <Container>
     94         <Section>
     95           <ThreadCommentView index={0} comment={props.firstComment} />
     96         </Section>
     97 
     98         <Section>
     99           <ThreadCommentWrite threadId={props.thread.id} onWritten={handleRefresh} />
    100           <ThreadCommentList startsFrom={idStartsFrom} comments={props.comments} />
    101           <Pagination
    102             page={props.page}
    103             totalCount={props.thread.commentCount ?? 0}
    104             pageSize={PAGE_SIZE}
    105           />
    106         </Section>
    107       </Container>
    108     </>
    109   )
    110 }