mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-10-18 14:13:21 +00:00
wip standalone msg reactions lists
This commit is contained in:
parent
4dfefdf848
commit
5ca90f2703
@ -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;
|
||||
|
@ -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);
|
103
src/js/components/events/ReactionsList.tsx
Normal file
103
src/js/components/events/ReactionsList.tsx
Normal 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;
|
Loading…
Reference in New Issue
Block a user