Files
SkinbaseNova/resources/js/components/Feed/PostActions.jsx

140 lines
4.6 KiB
JavaScript

import React, { useState } from 'react'
import axios from 'axios'
/**
* PostActions: Like toggle, Comment toggle, Share menu, Report
*/
export default function PostActions({
post,
isLoggedIn,
onCommentToggle,
onReactionChange,
}) {
const [liked, setLiked] = useState(post.viewer_liked ?? false)
const [likeCount, setLikeCount] = useState(post.reactions_count ?? 0)
const [busy, setBusy] = useState(false)
const [menuOpen, setMenuOpen] = useState(false)
const [shareMsg, setShareMsg] = useState(null)
const handleLike = async () => {
if (!isLoggedIn) {
window.location.href = '/login'
return
}
if (busy) return
setBusy(true)
try {
if (liked) {
await axios.delete(`/api/posts/${post.id}/reactions/like`)
setLiked(false)
setLikeCount((c) => Math.max(0, c - 1))
onReactionChange?.({ liked: false, count: Math.max(0, likeCount - 1) })
} else {
await axios.post(`/api/posts/${post.id}/reactions`, { reaction: 'like' })
setLiked(true)
setLikeCount((c) => c + 1)
onReactionChange?.({ liked: true, count: likeCount + 1 })
}
} catch {
// ignore
} finally {
setBusy(false)
}
}
const handleCopyLink = () => {
const url = `${window.location.origin}/@${post.author.username}/posts?post=${post.id}`
navigator.clipboard?.writeText(url)
setShareMsg('Link copied!')
setTimeout(() => setShareMsg(null), 2000)
setMenuOpen(false)
}
const handleReport = async () => {
setMenuOpen(false)
const reason = window.prompt('Why are you reporting this post? (required)')
if (!reason?.trim()) return
try {
await axios.post(`/api/posts/${post.id}/report`, { reason: reason.trim() })
alert('Report submitted. Thank you!')
} catch (err) {
if (err.response?.data?.message) {
alert(err.response.data.message)
}
}
}
return (
<div className="flex items-center gap-1 text-slate-400 relative">
{/* Like */}
<button
onClick={handleLike}
disabled={busy}
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm transition-colors ${
liked
? 'text-sky-400 bg-sky-500/10 hover:bg-sky-500/20'
: 'hover:bg-white/5 hover:text-slate-200'
}`}
title={liked ? 'Unlike' : 'Like'}
aria-label={liked ? 'Unlike this post' : 'Like this post'}
>
<i className={`fa-${liked ? 'solid' : 'regular'} fa-heart fa-fw text-xs`} />
<span className="tabular-nums">{likeCount > 0 && likeCount}</span>
</button>
{/* Comment toggle */}
<button
onClick={onCommentToggle}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm hover:bg-white/5 hover:text-slate-200 transition-colors"
title="Comment"
aria-label="Show comments"
>
<i className="fa-regular fa-comment fa-fw text-xs" />
<span className="tabular-nums">{post.comments_count > 0 && post.comments_count}</span>
</button>
{/* Share / More menu */}
<div className="relative ml-auto">
<button
onClick={() => setMenuOpen((v) => !v)}
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-sm hover:bg-white/5 hover:text-slate-200 transition-colors"
aria-label="More options"
>
<i className="fa-solid fa-ellipsis-h fa-fw text-xs" />
</button>
{menuOpen && (
<div
className="absolute right-0 bottom-full mb-1 w-44 rounded-xl border border-white/10 bg-[#10192e] shadow-2xl z-50 overflow-hidden"
onBlur={() => setMenuOpen(false)}
>
<button
onClick={handleCopyLink}
className="w-full text-left px-4 py-2.5 text-sm text-slate-300 hover:bg-white/5 flex items-center gap-2"
>
<i className="fa-solid fa-link fa-fw opacity-60" />
Copy link
</button>
{isLoggedIn && (
<button
onClick={handleReport}
className="w-full text-left px-4 py-2.5 text-sm text-rose-400 hover:bg-white/5 flex items-center gap-2"
>
<i className="fa-solid fa-flag fa-fw opacity-60" />
Report post
</button>
)}
</div>
)}
</div>
{/* Share feedback toast */}
{shareMsg && (
<span className="absolute -top-8 right-0 text-xs bg-slate-800 text-white px-2 py-1 rounded shadow">
{shareMsg}
</span>
)}
</div>
)
}