wip standalone msg reactions lists

This commit is contained in:
Martti Malmi 2023-06-29 14:29:44 +03:00
parent 4dfefdf848
commit 5ca90f2703
3 changed files with 185 additions and 70 deletions

View File

@ -16,7 +16,7 @@ import Torrent from '../Torrent';
import EventComponent from './EventComponent';
import EventDropdown from './EventDropdown';
import Reactions from './Reactions';
import Reactions from './ReactionButtons';
const MSG_TRUNCATE_LENGTH = 500;
const MSG_TRUNCATE_LINES = 8;

View File

@ -21,13 +21,15 @@ import SocialNetwork from '../../nostr/SocialNetwork';
import Identicon from '../Identicon';
import ZapModal from '../modal/Zap';
const Reactions = (props) => {
import ReactionsList from './ReactionsList';
const ReactionButtons = (props) => {
const [state, setState] = useState({
reposts: 0,
reposted: false,
likes: 0,
zappers: null as string[] | null,
totalZapped: '',
totalZapAmount: '',
liked: false,
zapped: false,
repostedBy: new Set<string>(),
@ -181,7 +183,7 @@ const Reactions = (props) => {
const zappers = zapEvents
.map((event) => Events.getZappingUser(event.id))
.filter((user) => user !== null) as string[];
const totalZapped = zapEvents.reduce((acc, event) => {
const totalZapAmount = zapEvents.reduce((acc, event) => {
const bolt11 = event?.tags.find((tag) => tag[0] === 'bolt11')[1];
if (!bolt11) {
console.log('Invalid zap, missing bolt11 tag');
@ -199,7 +201,8 @@ const Reactions = (props) => {
reposts: repostedBy.size,
reposted: repostedBy.has(myPub),
likes: likedBy.size,
totalZapped: totalZapped && formatAmount(totalZapped),
totalZapAmount,
formattedZapAmount: totalZapAmount && formatAmount(totalZapAmount),
zappers,
liked: likedBy.has(myPub),
likedBy,
@ -223,73 +226,82 @@ const Reactions = (props) => {
function renderReactionBtns() {
const s = state;
const likes = Array.from(s.likedBy) || [];
const reposts = Array.from(s.repostedBy) || [];
const zaps = Array.from(s.zappers || []);
console.log('111', likes, reposts, zaps);
return (
<div className="flex">
<a
className="btn-ghost flex-1 hover:bg-transparent hover:text-iris-blue btn content-center gap-2 rounded-none p-2 text-neutral-500"
onClick={() => replyBtnClicked()}
>
<ChatBubbleOvalLeftIcon width={18} />
<span>{s.replyCount || ''}</span>
</a>
{props.settings.showReposts ? (
<>
<a
className={`btn-ghost flex-1 hover:bg-transparent btn content-center gap-2 rounded-none p-2 ${
s.reposted ? 'text-iris-green' : 'hover:text-iris-green text-neutral-500'
}`}
onClick={(e) => repostBtnClicked(e)}
>
<ArrowPathIcon width={18} />
<span
className={`${s.showReposts ? 'active' : ''}`}
onClick={(e) => toggleReposts(e)}
<>
{props.standalone && (
<ReactionsList event={props.event} likes={likes} zaps={zaps} reposts={reposts} />
)}
<div className="flex">
<a
className="btn-ghost flex-1 hover:bg-transparent hover:text-iris-blue btn content-center gap-2 rounded-none p-2 text-neutral-500"
onClick={() => replyBtnClicked()}
>
<ChatBubbleOvalLeftIcon width={18} />
<span>{s.replyCount || ''}</span>
</a>
{props.settings.showReposts ? (
<>
<a
className={`btn-ghost flex-1 hover:bg-transparent btn content-center gap-2 rounded-none p-2 ${
s.reposted ? 'text-iris-green' : 'hover:text-iris-green text-neutral-500'
}`}
onClick={(e) => repostBtnClicked(e)}
>
{s.reposts || ''}
</span>
</a>
</>
) : (
''
)}
{props.settings.showLikes ? (
<>
<a
className={`btn-ghost flex-1 justify-center hover:bg-transparent btn content-center gap-2 rounded-none p-2 ${
s.liked ? 'text-iris-red' : 'hover:text-iris-red text-neutral-500'
}`}
onClick={(e) => likeBtnClicked(e)}
>
{s.liked ? <HeartIconFull width={18} /> : <HeartIcon width={18} />}
<span className={`${s.showLikes ? 'active' : ''}`} onClick={(e) => toggleLikes(e)}>
{s.likes || ''}
</span>
</a>
</>
) : (
''
)}
{props.settings.showZaps && state.lightning ? (
<>
<a
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setState((prevState) => ({ ...prevState, showZapModal: true }));
}}
className={`btn-ghost flex-1 hover:bg-transparent btn content-center gap-2 rounded-none p-2
<ArrowPathIcon width={18} />
<span
className={`${s.showReposts ? 'active' : ''}`}
onClick={(e) => toggleReposts(e)}
>
{s.reposts || ''}
</span>
</a>
</>
) : (
''
)}
{props.settings.showLikes ? (
<>
<a
className={`btn-ghost flex-1 justify-center hover:bg-transparent btn content-center gap-2 rounded-none p-2 ${
s.liked ? 'text-iris-red' : 'hover:text-iris-red text-neutral-500'
}`}
onClick={(e) => likeBtnClicked(e)}
>
{s.liked ? <HeartIconFull width={18} /> : <HeartIcon width={18} />}
<span className={`${s.showLikes ? 'active' : ''}`} onClick={(e) => toggleLikes(e)}>
{s.likes || ''}
</span>
</a>
</>
) : (
''
)}
{props.settings.showZaps && state.lightning ? (
<>
<a
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setState((prevState) => ({ ...prevState, showZapModal: true }));
}}
className={`btn-ghost flex-1 hover:bg-transparent btn content-center gap-2 rounded-none p-2
${s.zapped ? 'text-iris-orange' : 'text-neutral-500 hover:text-iris-orange'}`}
>
<BoltIcon width={18} />
<span className={`${s.showZaps ? 'active' : ''}`} onClick={(e) => toggleZaps(e)}>
{s.totalZapped || ''}
</span>
</a>
</>
) : (
''
)}
</div>
>
<BoltIcon width={18} />
<span className={`${s.showZaps ? 'active' : ''}`} onClick={(e) => toggleZaps(e)}>
{s.totalZapAmount || ''}
</span>
</a>
</>
) : (
''
)}
</div>
</>
);
}
@ -342,4 +354,4 @@ const Reactions = (props) => {
);
};
export default memo(Reactions);
export default memo(ReactionButtons);

View File

@ -0,0 +1,103 @@
import { memo, useState } from 'react';
import { Event, nip19 } from 'nostr-tools';
import { Link } from 'preact-router';
import { decodeInvoice, formatAmount } from '../../Lightning';
import Events from '../../nostr/Events';
import Identicon from '../Identicon';
import Modal from '../modal/Modal';
import Name from '../Name';
const Reaction = memo(
({ event }: { event: Event }) => {
const reactor = (event.kind === 9735 ? Events.getZappingUser(event.id) : event.pubkey) || '';
const invoice =
event.kind === 9735 ? event.tags?.find((tag) => tag[0] === 'bolt11')?.[1] : undefined;
const amount = invoice ? decodeInvoice(invoice)?.amount : undefined;
console.log('amount', amount, 'invoice', invoice, 'event', event);
return (
<Link
href={`/${nip19.npubEncode(reactor)}`}
key={event.id}
className="flex items-center gap-4"
>
<Identicon str={reactor} width={40} />
<div className="flex flex-col">
<Name pub={reactor} />
{amount && <small className="text-neutral-500">{formatAmount(amount / 1000)}</small>}
</div>
</Link>
);
},
(prevProps, nextProps) => prevProps.event.id === nextProps.event.id,
);
const ReactionsList = (props) => {
const { likes, reposts, zaps, totalZapAmount, formattedZapAmount } = props;
const [modalReactions, setModalReactions] = useState([] as Event[]);
const [modalTitle, setModalTitle] = useState('');
console.log(333, likes.length, reposts.length, zaps.length, totalZapAmount, formattedZapAmount);
return (
<>
<hr className="-mx-4 opacity-10" />
{modalReactions.length > 0 && (
<Modal showContainer={true} onClose={() => setModalReactions([])}>
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold">{modalTitle}</h2>
</div>
<div className="flex flex-col gap-4 overflow-y-scroll max-h-[50vh] w-96">
{modalReactions.map((event) => (
<Reaction key={event.id} event={event} />
))}
</div>
</Modal>
)}
<div className="flex items-center gap-4 py-2">
{likes.length > 0 && (
<div className="flex-shrink-0">
<a
onClick={() => {
setModalReactions(likes);
setModalTitle('Liked by');
}}
className="cursor-pointer hover:underline"
>
{likes.length} <span className="text-neutral-500">Likes</span>
</a>
</div>
)}
{reposts.length > 0 && (
<div className="flex-shrink-0">
<a
onClick={() => {
setModalReactions(reposts);
setModalTitle('Reposted by');
}}
className="cursor-pointer hover:underline"
>
{reposts.length} <span className="text-neutral-500">Reposts</span>
</a>
</div>
)}
{zaps.length > 0 && (
<div className="flex-shrink-0">
<a
onClick={() => {
setModalReactions(zaps);
setModalTitle('Zapped by');
}}
className="cursor-pointer hover:underline"
>
{zaps.length} <span className="text-neutral-500">Zaps</span>
{totalZapAmount > 0 && (
<small className="text-neutral-500"> ({formattedZapAmount})</small>
)}
</a>
</div>
)}
</div>
</>
);
};
export default ReactionsList;