import axios from 'axios' import { useEffect, useState, useRef } from 'react' import { Helmet } from 'react-helmet-async' import { useNavigate } from 'react-router-dom' import Form from '@/components/common/Form' import Label from '@/components/common/Label' import PageTitle from '@/components/common/PageTitle' import TextArea from '@/components/common/TextArea' import MainArea from '@/components/layout/MainArea' import { Button } from '@/components/ui/button' import { toast } from '@/components/ui/use-toast' import { API_BASE_URL, SITE_TITLE } from '@/config' import Forbidden from '@/pages/Forbidden' import type { User } from '@/types' type Props = { user: User | null } export default ({ user }: Props) => { if (!(['admin', 'member'].some (r => user?.role === r))) return const navigate = useNavigate () const [title, setTitle] = useState ('') const [titleAutoFlg, setTitleAutoFlg] = useState (true) const [titleLoading, setTitleLoading] = useState (false) const [url, setURL] = useState ('') const [thumbnailFile, setThumbnailFile] = useState (null) const [thumbnailPreview, setThumbnailPreview] = useState ('') const [thumbnailAutoFlg, setThumbnailAutoFlg] = useState (true) const [thumbnailLoading, setThumbnailLoading] = useState (false) const [tags, setTags] = useState ('') const previousURLRef = useRef ('') const handleSubmit = async () => { const formData = new FormData formData.append ('title', title) formData.append ('url', url) formData.append ('tags', tags) if (thumbnailFile) formData.append ('thumbnail', thumbnailFile) try { await axios.post (`${ API_BASE_URL }/posts`, formData, { headers: { 'Content-Type': 'multipart/form-data', 'X-Transfer-Code': localStorage.getItem ('user_code') ?? '' } }) toast ({ title: '投稿成功!' }) navigate ('/posts') } catch { toast ({ title: '投稿失敗', description: '入力を確認してください。' }) } } useEffect (() => { if (titleAutoFlg && url) fetchTitle () }, [titleAutoFlg]) useEffect (() => { if (thumbnailAutoFlg && url) fetchThumbnail () }, [thumbnailAutoFlg]) const handleURLBlur = () => { if (!(url) || url === previousURLRef.current) return if (titleAutoFlg) fetchTitle () if (thumbnailAutoFlg) fetchThumbnail () previousURLRef.current = url } const fetchTitle = async () => { setTitle ('') setTitleLoading (true) const res = await axios.get (`${ API_BASE_URL }/preview/title`, { params: { url }, headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } }) const data = res.data as { title: string } setTitle (data.title || '') setTitleLoading (false) } const fetchThumbnail = async () => { setThumbnailPreview ('') setThumbnailFile (null) setThumbnailLoading (true) if (thumbnailPreview) URL.revokeObjectURL (thumbnailPreview) const res = await axios.get (`${ API_BASE_URL }/preview/thumbnail`, { params: { url }, headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' }, responseType: 'blob' }) const data = res.data as Blob const imageURL = URL.createObjectURL (data) setThumbnailPreview (imageURL) setThumbnailFile (new File ([data], 'thumbnail.png', { type: data.type || 'image/png' })) setThumbnailLoading (false) } return ( {`広場に投稿を追加 | ${ SITE_TITLE }`}
広場に投稿を追加する {/* URL */}
setURL (e.target.value)} className="w-full border p-2 rounded" onBlur={handleURLBlur} />
{/* タイトル */}
setTitle (ev.target.value)} disabled={titleAutoFlg} />
{/* サムネール */}
{thumbnailAutoFlg ? (thumbnailLoading ?

Loading...

: !(thumbnailPreview) && (

URL から自動取得されます。

)) : ( { const file = e.target.files?.[0] if (file) { setThumbnailFile (file) setThumbnailPreview (URL.createObjectURL (file)) } }} />)} {thumbnailPreview && ( preview)}
{/* タグ */} {/* TextArea で自由形式にする */}