Remove profile reaction action

This commit is contained in:
lemon
2026-06-20 22:52:14 -07:00
parent 557063c0f3
commit bba7fb045a
3 changed files with 0 additions and 150 deletions
-136
View File
@@ -1,136 +0,0 @@
import { useState, useRef, useCallback } from 'react';
import { SmilePlus } from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { QuickReactMenu } from '@/components/QuickReactMenu';
import { Button } from '@/components/ui/button';
import { useAppContext } from '@/hooks/useAppContext';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useNostrPublish } from '@/hooks/useNostrPublish';
import { useEmojiUsage } from '@/hooks/useEmojiUsage';
import { useToast } from '@/hooks/useToast';
import { impactLight } from '@/lib/haptics';
import { invalidateEventStats } from '@/lib/invalidateEventStats';
import type { NostrEvent } from '@nostrify/nostrify';
interface ProfileReactionButtonProps {
/** The kind 0 metadata event for the profile being reacted to. */
profileEvent: NostrEvent;
/** Optional extra class names for the trigger button. */
className?: string;
}
/**
* Emoji reaction button for user profiles.
* Opens an emoji picker and publishes a kind 7 reaction targeting
* the user's kind 0 profile event with `a`, `e`, and `p` tags.
*/
export function ProfileReactionButton({ profileEvent, className }: ProfileReactionButtonProps) {
const { user } = useCurrentUser();
const { mutate: publishEvent } = useNostrPublish();
const { trackEmojiUsage } = useEmojiUsage();
const { toast } = useToast();
const queryClient = useQueryClient();
const { config } = useAppContext();
const statsPubkey = config.nip85StatsPubkey;
const [menuOpen, setMenuOpen] = useState(false);
const pickerExpandedRef = useRef(false);
const justClosedRef = useRef(false);
const handleReact = useCallback((emoji: string, emojiTag?: string[]) => {
if (!user) return;
impactLight();
trackEmojiUsage(emoji);
const tags: string[][] = [
['e', profileEvent.id],
['p', profileEvent.pubkey],
['a', `0:${profileEvent.pubkey}:`],
['k', '0'],
];
if (emojiTag) tags.push(emojiTag);
publishEvent(
{
kind: 7,
content: emoji,
created_at: Math.floor(Date.now() / 1000),
tags,
},
{
onSuccess: () => {
toast({ title: 'Reaction sent!' });
// Bump reaction count on the profile. Profile reactions target the
// kind 0 event by id, so useNip85EventStats refresh covers it. Also
// refresh the addressable `0:<pubkey>:` key in case any consumer
// reads profile stats via useNip85AddrStats.
setTimeout(() => {
invalidateEventStats(queryClient, profileEvent, statsPubkey);
queryClient.invalidateQueries({
queryKey: ['nip85-addr-stats', `0:${profileEvent.pubkey}:`, statsPubkey],
});
queryClient.invalidateQueries({
queryKey: ['nip85-addr-stats', `0:${profileEvent.pubkey}:`],
});
}, 3000);
},
},
);
}, [user, profileEvent, publishEvent, trackEmojiUsage, toast, queryClient, statsPubkey]);
if (!user) return null;
return (
<Popover
open={menuOpen}
onOpenChange={(open) => {
if (open && justClosedRef.current) return;
if (!open) pickerExpandedRef.current = false;
setMenuOpen(open);
}}
>
<PopoverTrigger asChild>
<Button
variant="outline"
size="icon"
className={className ?? 'rounded-full size-10'}
title="React to this profile"
onClick={(e) => {
e.stopPropagation();
if (justClosedRef.current) return;
setMenuOpen((prev) => !prev);
}}
>
<SmilePlus className="size-5" />
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto p-0 border-0 bg-transparent shadow-none"
side="top"
align="start"
onClick={(e) => e.stopPropagation()}
onOpenAutoFocus={(e) => e.preventDefault()}
>
<QuickReactMenu
eventId={profileEvent.id}
eventPubkey={profileEvent.pubkey}
eventKind={0}
onReact={handleReact}
onExpandChange={(expanded) => {
pickerExpandedRef.current = expanded;
}}
onClose={() => {
pickerExpandedRef.current = false;
justClosedRef.current = true;
setMenuOpen(false);
setTimeout(() => {
justClosedRef.current = false;
}, 300);
}}
/>
</PopoverContent>
</Popover>
);
}
@@ -28,7 +28,6 @@ import { EmojifiedText } from '@/components/CustomEmoji';
import { FollowToggleButton } from '@/components/FollowButton';
import { Nip05Badge } from '@/components/Nip05Badge';
import { PledgeCard } from '@/components/PledgeCard';
import { ProfileReactionButton } from '@/components/ProfileReactionButton';
import { OrganizationsAllDialog } from '@/components/profile/OrganizationsAllDialog';
import { useCampaignModeration } from '@/hooks/useCampaignModeration';
import { useProfileOrganizations, type ProfileOrganization } from '@/hooks/useProfileOrganizations';
@@ -91,8 +90,6 @@ interface ProfileIdentityRailProps {
onDonate: (campaign: ParsedCampaign) => void;
/** Whether the viewer can take any action (logged in). Disables follow when null. */
canFollow: boolean;
/** Latest kind-0 event used by ProfileReactionButton; falls back to metadataEvent. */
authorEvent: NostrEvent | undefined;
}
const RAIL_CAMPAIGN_LIMIT = 2;
@@ -143,7 +140,6 @@ export function ProfileIdentityRail({
onTabChange,
onDonate,
canFollow,
authorEvent,
}: ProfileIdentityRailProps) {
if (isAuthorLoading) {
return (
@@ -204,7 +200,6 @@ export function ProfileIdentityRail({
onFollowersOpen={onFollowersOpen}
onFollowingOpen={onFollowingOpen}
onTabChange={onTabChange}
authorEvent={authorEvent}
/>
<ProfileOverviewSections
pubkey={pubkey}
@@ -247,7 +242,6 @@ interface ProfileIdentityHeaderProps {
onFollowersOpen: () => void;
onFollowingOpen: () => void;
onTabChange: (tabId: string) => void;
authorEvent: NostrEvent | undefined;
className?: string;
/**
* Suppress the internal action bar (Edit Profile / QR / more, or
@@ -288,7 +282,6 @@ export function ProfileIdentityHeader({
onFollowersOpen,
onFollowingOpen,
onTabChange,
authorEvent,
className,
hideActionBar = false,
}: ProfileIdentityHeaderProps) {
@@ -346,7 +339,6 @@ export function ProfileIdentityHeader({
onToggleFollow={onToggleFollow}
onMoreMenuOpen={onMoreMenuOpen}
onFollowQROpen={onFollowQROpen}
authorEvent={authorEvent}
onchainCampaigns={onchainCampaigns}
onDonate={onDonate}
/>
@@ -526,7 +518,6 @@ export function ActionBar({
onToggleFollow,
onMoreMenuOpen,
onFollowQROpen,
authorEvent,
onchainCampaigns,
onDonate,
align = 'start',
@@ -538,7 +529,6 @@ export function ActionBar({
onToggleFollow: () => void;
onMoreMenuOpen: () => void;
onFollowQROpen: () => void;
authorEvent: NostrEvent | undefined;
onchainCampaigns: ParsedCampaign[];
onDonate: (campaign: ParsedCampaign) => void;
/**
@@ -622,7 +612,6 @@ export function ActionBar({
</DropdownMenuContent>
</DropdownMenu>
) : null}
{authorEvent && <ProfileReactionButton profileEvent={authorEvent} />}
<Button
variant="outline"
size="icon"
-3
View File
@@ -1459,7 +1459,6 @@ function FollowersListModal({ pubkey, open, onOpenChange, displayName }: Followe
onTabChange={(id) => handleTabChange(id)}
onDonate={openDonateForCampaign}
canFollow={!!user}
authorEvent={authorEvent}
/>
</aside>
)}
@@ -1534,7 +1533,6 @@ function FollowersListModal({ pubkey, open, onOpenChange, displayName }: Followe
onToggleFollow={handleToggleFollow}
onMoreMenuOpen={() => setMoreMenuOpen(true)}
onFollowQROpen={() => setFollowQROpen(true)}
authorEvent={authorEvent}
onchainCampaigns={profileCampaignStats.campaigns.filter((c) => !!c.wallets?.onchain)}
onDonate={openDonateForCampaign}
/>
@@ -1573,7 +1571,6 @@ function FollowersListModal({ pubkey, open, onOpenChange, displayName }: Followe
onFollowersOpen={() => setFollowersModalOpen(true)}
onFollowingOpen={() => setFollowingModalOpen(true)}
onTabChange={handleTabChange}
authorEvent={authorEvent}
/>
{/* Tab bar — sticky to the top of the page scroll once