import React, { useEffect, useState, useRef } from 'react' import { Link, useLocation, useParams, useNavigate } from 'react-router-dom' import axios from 'axios' import { API_BASE_URL, SITE_TITLE } from '../config' import NicoViewer from '../components/NicoViewer' import { Button } from '@/components/ui/button' import { toast } from '@/components/ui/use-toast' import { cn } from '@/lib/utils' import type { Post, Tag } from '@/types' type Props = { posts: Post[] setPosts: (posts: Post[]) => void } const PostNewPage = () => { const location = useLocation () 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 [tagIds, setTagIds] = useState ([]) const previousURLRef = useRef ('') const handleSubmit = () => { const formData = new FormData () formData.append ('title', title) formData.append ('url', url) formData.append ('tags', JSON.stringify (tagIds)) formData.append ('thumbnail', thumbnailFile) void (axios.post (`${ API_BASE_URL }/posts`, formData, { headers: { 'Content-Type': 'multipart/form-data', 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } }) .then (() => { toast ({ title: '投稿成功!' }) navigate ('/posts') }) .catch (e => toast ({ title: '投稿失敗', description: '入力を確認してください。' }))) } document.title = `広場に投稿を追加 | ${ SITE_TITLE }` useEffect (() => { void (axios.get ('/api/tags') .then (res => setTags (res.data)) .catch (() => toast ({ title: 'タグ一覧の取得失敗' }))) }, []) 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 = () => { setTitle ('') setTitleLoading (true) void (axios.get (`${ API_BASE_URL }/preview/title`, { params: { url }, headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } }) .then (res => { setTitle (res.data.title || '') setTitleLoading (false) }) .finally (() => setTitleLoading (false))) } const fetchThumbnail = () => { setThumbnailPreview ('') setThumbnailFile (null) setThumbnailLoading (true) if (thumbnailPreview) URL.revokeObjectURL (thumbnailPreview) void (axios.get (`${ API_BASE_URL }/preview/thumbnail`, { params: { url }, headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' }, responseType: 'blob' }) .then (res => { const imageURL = URL.createObjectURL (res.data) setThumbnailPreview (imageURL) setThumbnailFile (new File ([res.data], 'thumbnail.png', { type: res.data.type || 'image/png' })) setThumbnailLoading (false) }) .finally (() => setThumbnailLoading (false))) } return (

広場に投稿を追加する

{/* URL */}
setURL (e.target.value)} className="w-full border p-2 rounded" onBlur={handleURLBlur} />
{/* タイトル */}
setTitle (e.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)}
{/* タグ */}
{/* 送信 */}
) } export default PostNewPage