|
- import { useEffect, useState } from 'react'
- import { Helmet } from 'react-helmet-async'
- import { useParams } from 'react-router-dom'
-
- import TagLink from '@/components/TagLink'
- import WikiBody from '@/components/WikiBody'
- import Label from '@/components/common/Label'
- import PageTitle from '@/components/common/PageTitle'
- import TabGroup, { Tab } from '@/components/common/TabGroup'
- import TagInput from '@/components/common/TagInput'
- import MainArea from '@/components/layout/MainArea'
- import { Button } from '@/components/ui/button'
- import { toast } from '@/components/ui/use-toast'
- import { SITE_TITLE } from '@/config'
- import { apiGet, apiPut } from '@/lib/api'
-
- import type { FC } from 'react'
-
- import type { Material, Tag } from '@/types'
-
- type MaterialWithTag = Material & { tag: Tag }
-
-
- const MaterialDetailPage: FC = () => {
- const { id } = useParams ()
-
- const [file, setFile] = useState<File | null> (null)
- const [filePreview, setFilePreview] = useState ('')
- const [loading, setLoading] = useState (false)
- const [material, setMaterial] = useState<MaterialWithTag | null> (null)
- const [sending, setSending] = useState (false)
- const [tag, setTag] = useState ('')
- const [url, setURL] = useState ('')
-
- const handleSubmit = async () => {
- const formData = new FormData
- if (tag.trim ())
- formData.append ('tag', tag)
- if (file)
- formData.append ('file', file)
- if (url.trim ())
- formData.append ('url', url)
-
- try
- {
- setSending (true)
- const data = await apiPut<Material> (`/materials/${ id }`, formData)
- setMaterial (data)
- toast ({ title: '更新成功!' })
- }
- catch
- {
- toast ({ title: '更新失敗……', description: '入力を見直してください.' })
- }
- finally
- {
- setSending (false)
- }
- }
-
- useEffect (() => {
- if (!(id))
- return
-
- void (async () => {
- try
- {
- setLoading (true)
- const data = await apiGet<MaterialWithTag> (`/materials/${ id }`)
- setMaterial (data)
- setTag (data.tag.name)
- if (data.file && data.contentType)
- {
- setFilePreview (data.file)
- setFile (new File ([await (await fetch (data.file)).blob ()],
- data.file,
- { type: data.contentType }))
- }
- setURL (data.url ?? '')
- }
- finally
- {
- setLoading (false)
- }
- }) ()
- }, [id])
-
- return (
- <MainArea>
- {material && (
- <Helmet>
- <title>{`${ material.tag.name } 素材照会 | ${ SITE_TITLE }`}</title>
- </Helmet>)}
-
- {loading ? 'Loading...' : (material && (
- <>
- <PageTitle>
- <TagLink
- tag={material.tag}
- withWiki={false}
- withCount={false}/>
- </PageTitle>
-
- {(material.file && material.contentType) && (
- (/image\/.*/.test (material.contentType) && (
- <img src={material.file} alt={material.tag.name || undefined}/>))
- || (/video\/.*/.test (material.contentType) && (
- <video src={material.file} controls/>))
- || (/audio\/.*/.test (material.contentType) && (
- <audio src={material.file} controls/>)))}
-
- <TabGroup>
- <Tab name="Wiki">
- <WikiBody
- title={material.tag.name}
- body={material.wikiPageBody ?? undefined}/>
- </Tab>
-
- <Tab name="編輯">
- <div className="max-w-wl pt-2 space-y-4">
- {/* タグ */}
- <div>
- <Label>タグ</Label>
- <TagInput value={tag} setValue={setTag}/>
- </div>
-
- {/* ファイル */}
- <div>
- <Label>ファイル</Label>
- <input
- type="file"
- accept="image/*,video/*,audio/*"
- onChange={e => {
- const f = e.target.files?.[0]
- setFile (f ?? null)
- setFilePreview (f ? URL.createObjectURL (f) : '')
- }}/>
- {(file && filePreview) && (
- (/image\/.*/.test (file.type) && (
- <img
- src={filePreview}
- alt="preview"
- className="mt-2 max-h-48 rounded border"/>))
- || (/video\/.*/.test (file.type) && (
- <video
- src={filePreview}
- controls
- className="mt-2 max-h-48 rounded border"/>))
- || (/audio\/.*/.test (file.type) && (
- <audio
- src={filePreview}
- controls
- className="mt-2 max-h-48"/>))
- || (
- <p className="text-red-600 dark:text-red-400">
- その形式のファイルには対応していません.
- </p>))}
- </div>
-
- {/* 参考 URL */}
- <div>
- <Label>参考 URL</Label>
- <input
- type="url"
- value={url}
- onChange={e => setURL (e.target.value)}
- className="w-full border p-2 rounded"/>
- </div>
-
- {/* 送信 */}
- <Button
- onClick={handleSubmit}
- className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400"
- disabled={sending}>
- 更新
- </Button>
- </div>
- </Tab>
- </TabGroup>
- </>))}
- </MainArea>)
- }
-
- export default MaterialDetailPage
|