#49 ぼちぼち

This commit is contained in:
2025-06-28 02:32:40 +09:00
parent ba1c1f1adf
commit 8020586ec6
19 changed files with 168 additions and 106 deletions
+111
View File
@@ -0,0 +1,111 @@
import React, { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet'
import { Link, useLocation, useParams } 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 MainArea from '@/components/layout/MainArea'
import TagDetailSidebar from '@/components/TagDetailSidebar'
import PostEditForm from '@/components/PostEditForm'
import TabGroup, { Tab } from '@/components/common/TabGroup'
import type { Post, Tag, User } from '@/types'
type Props = { user: User }
export default ({ user }: Props) => {
const { id } = useParams ()
const location = useLocation ()
const [post, setPost] = useState<Post | null> (null)
const [editing, setEditing] = useState (true)
const changeViewedFlg = () => {
if (post?.viewed)
{
void (axios.delete (
`${ API_BASE_URL }/posts/${ id }/viewed`,
{ headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } })
.then (res => setPost (post => ({ ...post, viewed: false })))
.catch (err => toast ({ title: '失敗……',
description: '通信に失敗しました……' })))
}
else
{
void (axios.post (
`${ API_BASE_URL }/posts/${ id }/viewed`,
{ },
{ headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } })
.then (res => setPost (post => ({ ...post, viewed: true })))
.catch (err => toast ({ title: '失敗……',
description: '通信に失敗しました……' })))
}
}
useEffect (() => {
if (!(id))
return
void (axios.get (`${ API_BASE_URL }/posts/${ id }`, { headers: {
'X-Transfer-Code': localStorage.getItem ('user_code') || '' } })
.then (res => setPost (res.data))
.catch (err => console.error ('うんち!', err)))
}, [id])
useEffect (() => {
setEditing (false)
}, [post])
useEffect (() => {
if (!(editing))
setEditing (true)
}, [editing])
const url = post ? new URL (post.url) : null
const nicoFlg = url?.hostname.split ('.').slice (-2).join ('.') === 'nicovideo.jp'
const videoId = (nicoFlg
? url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)[0]
: '')
const viewedClass = (post?.viewed
? 'bg-blue-600 hover:bg-blue-700'
: 'bg-gray-500 hover:bg-gray-600')
return (
<>
<Helmet>
{post && <title>{`${ post.title || post.url } | ${ SITE_TITLE }`}</title>}
</Helmet>
<TagDetailSidebar post={post} />
<MainArea>
{post
? (
<>
{nicoFlg
? (
<NicoViewer id={videoId}
width="640"
height="360" />)
: <img src={post.thumbnail} alt={post.url} className="mb-4 w-full" />}
<Button onClick={changeViewedFlg}
className={cn ('text-white', viewedClass)}>
{post.viewed ? '閲覧済' : '未閲覧'}
</Button>
<TabGroup>
{['admin', 'member'].some (r => r === user.role) && editing &&
<Tab name="編輯">
<PostEditForm post={post}
onSave={newPost => {
setPost (newPost)
toast ({ description: '更新しました.' })
}} />
</Tab>}
</TabGroup>
</>)
: 'Loading...'}
</MainArea>
</>)
}