/** * Block/mute toggle button for user actions. * Used in user profiles and post context menus. * Shows a login prompt toast for unauthenticated users. * On first use, displays a confirmation dialog explaining the action. * @see specs/prd-web.md Section M8 */ 'use client' import { useEffect, useRef, useState } from 'react' import { Prohibit, SpeakerSimpleSlash, WarningCircle } from '@phosphor-icons/react' import { cn } from '@/lib/utils' import { blockUser, unblockUser, muteUser, unmuteUser } from '@/lib/api/client' import { useAuth } from '@/hooks/use-auth' import { useRequireAuth } from '@/hooks/use-require-auth' interface BlockMuteButtonProps { targetDid: string action: 'block' | 'mute' isActive: boolean onToggle: (newState: boolean) => void className?: string } const STORAGE_KEYS = { block: 'barazo_block_explained', mute: 'barazo_mute_explained', } as const export function BlockMuteButton({ targetDid, action, isActive, onToggle, className, }: BlockMuteButtonProps) { const { getAccessToken } = useAuth() const { requireAuth } = useRequireAuth() const [loading, setLoading] = useState(false) const [error, setError] = useState(false) const [dialogOpen, setDialogOpen] = useState(false) const dialogRef = useRef(null) useEffect(() => { const dialog = dialogRef.current if (!dialog) return if (dialogOpen) { dialog.showModal() } else if (dialog.open) { dialog.close() } }, [dialogOpen]) const executeAction = () => { requireAuth(async () => { setLoading(true) setError(false) const token = getAccessToken() if (!token) { setLoading(false) return } try { if (action === 'block') { if (isActive) { await unblockUser(targetDid, token) } else { await blockUser(targetDid, token) } } else { if (isActive) { await unmuteUser(targetDid, token) } else { await muteUser(targetDid, token) } } onToggle(!isActive) } catch { setError(true) } finally { setLoading(false) } }) } const handleClick = () => { if (isActive) { executeAction() return } const storageKey = STORAGE_KEYS[action] if (!localStorage.getItem(storageKey)) { setDialogOpen(true) return } executeAction() } const handleConfirm = () => { localStorage.setItem(STORAGE_KEYS[action], '1') setDialogOpen(false) executeAction() } const handleCancel = () => { setDialogOpen(false) } const Icon = action === 'block' ? Prohibit : SpeakerSimpleSlash const label = action === 'block' ? (isActive ? 'Unblock' : 'Block') : isActive ? 'Unmute' : 'Mute' return (
{error && ( )} {dialogOpen && (
{action === 'block' ? ( <>

Block this user?

Blocking completely removes someone from your experience on this forum:

  • Their posts and replies are hidden from your feed
  • They won't appear in search results

You can unblock them anytime from their profile or your settings.

) : ( <>

Mute this user?

Muting reduces someone's visibility without fully removing them:

  • Their posts are collapsed but you can expand them to read
  • They won't know they've been muted

You can unmute them anytime from their profile or your settings.

)}
)}
) }