[...path].tsx (4470B)
1 import { SubmitButton } from '@/components/elements/Button' 2 import Title from '@/components/elements/Title' 3 import Field from '@/components/form/Field' 4 import Fields from '@/components/form/Fields' 5 import Form from '@/components/form/Form' 6 import Container from '@/components/layout/Container' 7 import Divider from '@/components/layout/Divider' 8 import Hero from '@/components/layout/Hero' 9 import Section from '@/components/layout/Section' 10 import { Pagination } from '@/components/Pagination' 11 import ThreadList from '@/components/threads/ThreadList' 12 import WikiBase from '@/components/wiki/WikiBase' 13 import { ApiError } from '@/lib/apierror' 14 import { withConnection } from '@/lib/model_helpers' 15 import { Thread } from '@/lib/models/thread' 16 import { getWikiAndPageACLViaPath } from '@/lib/models/wiki_acl' 17 import { countWikiTalks, listWikiTalks } from '@/lib/models/wiki_talk' 18 import { parseIntOrDefault } from '@/lib/utils/number' 19 import { CreateTalkResponse } from '@/pages/api/talks/[slug]/[...path]' 20 import { GetServerSideProps } from 'next' 21 import { useRouter } from 'next/router' 22 import { useState } from 'react' 23 24 const PAGE_SIZE = 10 25 26 export interface TestPageProps { 27 wikiSlug: string 28 pageId: number 29 pagePath: string 30 talks: Thread[] 31 counts: number 32 page: number 33 } 34 35 export const getServerSideProps: GetServerSideProps<TestPageProps> = async (context) => { 36 const { slug, path: paths } = context.query 37 if (typeof slug !== 'string' || !Array.isArray(paths)) { 38 return { 39 notFound: true, 40 } 41 } 42 43 const path = paths.join('/') 44 45 const page = Math.max(1, parseIntOrDefault(context.query.page, 1)) 46 47 return await withConnection(async (conn) => { 48 const aclInfo = await getWikiAndPageACLViaPath(conn, [slug, path]) 49 if (aclInfo == null || aclInfo.pageId == null) { 50 return { notFound: true } 51 } 52 53 const talks = await listWikiTalks(conn, [aclInfo.pageId, PAGE_SIZE, (page - 1) * PAGE_SIZE]) 54 const counts = await countWikiTalks(conn, [aclInfo.pageId]) 55 56 return { 57 props: { 58 wikiSlug: slug, 59 pageId: aclInfo.pageId, 60 pagePath: path, 61 talks: talks, 62 counts: counts, 63 page: page, 64 }, 65 } 66 }) 67 } 68 69 export default function TestPage (props: TestPageProps) { 70 return ( 71 <WikiBase pageKind={'talk'} title={props.pagePath}> 72 <Section> 73 {props.talks.length === 0 ? ( 74 <div>No talks</div> 75 ) : ( 76 <> 77 <ThreadList threads={props.talks}/> 78 <Pagination 79 page={props.page} 80 totalCount={props.counts} 81 pageSize={PAGE_SIZE} 82 /> 83 </> 84 )} 85 </Section> 86 87 <Divider/> 88 89 <Section> 90 <Title>새 주제 만들기</Title> 91 <NewTalk {...props} /> 92 </Section> 93 </WikiBase> 94 ) 95 } 96 97 function NewTalk (props: TestPageProps) { 98 const router = useRouter() 99 100 const [title, setTitle] = useState('') 101 const [content, setContent] = useState('') 102 103 const [isLoading, setLoading] = useState(false) 104 const [submitError, setSubmitError] = useState<ApiError | null>(null) 105 106 const handleSubmit = () => { 107 setLoading(true) 108 109 !(async () => { 110 const res = await fetch(`/api/talks/${props.wikiSlug}/${props.pagePath}`, { 111 method: 'POST', 112 headers: { 113 'Content-Type': 'application/json', 114 }, 115 body: JSON.stringify({ 116 title: title, 117 content: content, 118 }), 119 }) 120 121 const data = await res.json() 122 123 if (!res.ok) { 124 setLoading(false) 125 setSubmitError(data) 126 return 127 } 128 129 await router.push(`/threads/${(data as CreateTalkResponse).thread}`) 130 })().catch((err) => { 131 setLoading(false) 132 console.error(err) 133 }) 134 } 135 136 return ( 137 <> 138 <Form onSubmit={handleSubmit}> 139 <Fields> 140 <Field 141 type="text" 142 placeholder="제목" 143 value={title} 144 onValueChange={setTitle} 145 disabled={isLoading} 146 color={submitError ? 'error' : undefined} 147 /> 148 149 <Field 150 type="textarea" 151 placeholder="내용" 152 value={content} 153 onValueChange={setContent} 154 disabled={isLoading} 155 color={submitError ? 'error' : undefined} 156 message={submitError ? submitError.message : undefined} 157 /> 158 159 <SubmitButton value="만들기"/> 160 </Fields> 161 </Form> 162 </> 163 ) 164 }