dh_demo

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

[...path].tsx (3353B)


      1 import { useSocket } from '@/components/contexts/SocketContext'
      2 import { useToken } from '@/components/contexts/TokenContext'
      3 import { SubmitButton } from '@/components/elements/Button'
      4 import Fields from '@/components/form/Fields'
      5 import Form from '@/components/form/Form'
      6 import Section from '@/components/layout/Section'
      7 import WikiBase from '@/components/wiki/WikiBase'
      8 import WikiEditor from '@/components/wiki/WikiEditor'
      9 import { useForm } from '@/lib/hooks/use_form'
     10 import { withConnection } from '@/lib/model_helpers'
     11 import { getWikiViaSlug, WikiInfo } from '@/lib/models/wiki_info'
     12 import { getWikiRawPage, WikiRawPage } from '@/lib/models/wiki_page'
     13 import { ACL_ACTION_WRITE, resolveACL } from '@/lib/security/acl'
     14 import { authenticationFromCookies } from '@/lib/security/token'
     15 import { getSlugAndPath } from '@/lib/utils/wiki'
     16 import { GetServerSideProps } from 'next'
     17 import { useRouter } from 'next/router'
     18 import { useEffect } from 'react'
     19 import toast from 'react-hot-toast'
     20 
     21 export interface WikiEditPageProps {
     22   wiki: WikiInfo
     23   page?: WikiRawPage
     24 }
     25 
     26 export const getServerSideProps: GetServerSideProps<WikiEditPageProps> = async (context) => {
     27   const [slug, path] = getSlugAndPath(context)
     28   if (slug == null || path == null) {
     29     return { notFound: true }
     30   }
     31 
     32   const token = authenticationFromCookies(context.req.cookies)
     33 
     34   return await withConnection(async (conn) => {
     35     const wiki = await getWikiViaSlug(conn, [slug])
     36     if (wiki == null || !resolveACL(token, wiki.acl, ACL_ACTION_WRITE)) {
     37       return { notFound: true }
     38     }
     39 
     40     const page = await getWikiRawPage(conn, [wiki.id, path])
     41     if (page == null) {
     42       return {
     43         props: {
     44           wiki: wiki,
     45         },
     46       }
     47     }
     48 
     49     if (!resolveACL(token, page.acl, ACL_ACTION_WRITE)) {
     50       return { notFound: true }
     51     }
     52 
     53     return {
     54       props: {
     55         wiki: wiki,
     56         page: page,
     57       },
     58     }
     59   })
     60 }
     61 
     62 interface WikiEditFormFields {
     63   content: string
     64 }
     65 
     66 export default function WikiEditPage (props: WikiEditPageProps) {
     67   const router = useRouter()
     68   const socket = useSocket()
     69   const token = useToken()
     70 
     71   const [slug, path] = getSlugAndPath(router)
     72 
     73   // 다른 사용자가 문서를 편집했을 때
     74   useEffect(() => {
     75     return socket.on('pageChange', ({ payload }) => {
     76       if (payload !== token?.uid?.toString()) {
     77         toast('다른 사용자가 이 문서를 편집했습니다.')
     78       } else {
     79         toast('문서가 편집되었습니다.')
     80       }
     81     })
     82   }, [])
     83 
     84   const [fields, updateFields, submit, isLoading, result, error] = useForm<WikiEditFormFields>(
     85     { method: 'PUT', url: `/api/wiki/${slug}/${path}` },
     86     { content: props.page?.content ?? '' },
     87     () => {
     88       router.push(`/wiki/${slug}/${path}`)
     89         .catch(console.error)
     90     }
     91   )
     92 
     93   return (
     94     <WikiBase title={(
     95       <>
     96         <span>편집: {path}</span>
     97         {props.page == null && (
     98           <small> (새 문서 만들기)</small>
     99         )}
    100       </>
    101     )} pageKind="edit">
    102       <Section>
    103         <WikiEditor
    104           value={fields.content}
    105           onValueChange={updateFields.bind(null, 'content')}
    106         />
    107 
    108         <Form onSubmit={submit}>
    109           <Fields>
    110             <SubmitButton color="primary" disabled={isLoading} value="저장"/>
    111           </Fields>
    112         </Form>
    113       </Section>
    114     </WikiBase>
    115   )
    116 }