@ -13,6 +13,7 @@ import { Icon } from "element/icon";
|
||||
import { Emoji as EmojiComponent } from "element/emoji";
|
||||
import { Profile } from "./profile";
|
||||
import { Text } from "element/text";
|
||||
import { useMute } from "element/mute-button";
|
||||
import { SendZapsDialog } from "element/send-zap";
|
||||
import { CollapsibleEvent } from "element/collapsible";
|
||||
import { useLogin } from "hooks/login";
|
||||
@ -55,6 +56,7 @@ export function ChatMessage({
|
||||
const emojiRef = useRef(null);
|
||||
const isTablet = useMediaQuery("(max-width: 1020px)");
|
||||
const isHovering = useHover(ref);
|
||||
const { mute } = useMute(ev.pubkey);
|
||||
const [showZapDialog, setShowZapDialog] = useState(false);
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||
const login = useLogin();
|
||||
@ -62,6 +64,8 @@ export function ChatMessage({
|
||||
System,
|
||||
inView?.isIntersecting ? ev.pubkey : undefined
|
||||
);
|
||||
const shouldShowMuteButton =
|
||||
ev.pubkey !== streamer && ev.pubkey != login?.pubkey;
|
||||
const zapTarget = profile?.lud16 ?? profile?.lud06;
|
||||
const zaps = useMemo(() => {
|
||||
return reactions
|
||||
@ -132,11 +136,16 @@ export function ChatMessage({
|
||||
const topOffset = ref.current?.getBoundingClientRect().top;
|
||||
const leftOffset = ref.current?.getBoundingClientRect().left;
|
||||
|
||||
function pickEmoji(ev: React.MouseEvent) {
|
||||
ev.stopPropagation();
|
||||
function pickEmoji(e: React.MouseEvent) {
|
||||
e.stopPropagation();
|
||||
setShowEmojiPicker(!showEmojiPicker);
|
||||
}
|
||||
|
||||
async function muteUser(e: React.MouseEvent) {
|
||||
e.stopPropagation();
|
||||
mute();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@ -229,6 +238,11 @@ export function ChatMessage({
|
||||
<button className="message-zap-button" onClick={pickEmoji}>
|
||||
<Icon name="face" className="message-zap-button-icon" />
|
||||
</button>
|
||||
{shouldShowMuteButton && (
|
||||
<button className="message-zap-button" onClick={muteUser}>
|
||||
<Icon name="user-x" className="message-zap-button-icon" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { useMemo } from "react";
|
||||
import { useLogin } from "hooks/login";
|
||||
import AsyncButton from "element/async-button";
|
||||
import { Login, System } from "index";
|
||||
import { MUTED } from "const";
|
||||
|
||||
export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
||||
export function useMute(pubkey: string) {
|
||||
const login = useLogin();
|
||||
const { tags, content } = login!.muted;
|
||||
const muted = tags.filter((t) => t.at(0) === "p");
|
||||
const isMuted = muted.find((t) => t.at(1) === pubkey);
|
||||
const muted = useMemo(() => tags.filter((t) => t.at(0) === "p"), [tags]);
|
||||
const isMuted = useMemo(
|
||||
() => muted.find((t) => t.at(1) === pubkey),
|
||||
[pubkey, muted]
|
||||
);
|
||||
|
||||
async function unmute() {
|
||||
const pub = login?.publisher();
|
||||
@ -43,6 +47,12 @@ export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
return { isMuted, mute, unmute };
|
||||
}
|
||||
|
||||
export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
||||
const { isMuted, mute, unmute } = useMute(pubkey);
|
||||
|
||||
return (
|
||||
<AsyncButton
|
||||
type="button"
|
||||
|
@ -42,17 +42,19 @@ export function useStreamsFeed(tag?: string) {
|
||||
return [];
|
||||
}, [feed.data]);
|
||||
|
||||
const live = feedSorted.filter(
|
||||
(a) => findTag(a, "status") === StreamState.Live
|
||||
).sort(sortStarts);
|
||||
const planned = feedSorted.filter(
|
||||
(a) => findTag(a, "status") === StreamState.Planned
|
||||
).sort(sortStarts);
|
||||
const ended = feedSorted.filter((a) => {
|
||||
const hasEnded = findTag(a, "status") === StreamState.Ended;
|
||||
const recording = findTag(a, "recording") ?? "";
|
||||
return hasEnded && recording?.length > 0;
|
||||
}).sort(sortCreatedAt);
|
||||
const live = feedSorted
|
||||
.filter((a) => findTag(a, "status") === StreamState.Live)
|
||||
.sort(sortStarts);
|
||||
const planned = feedSorted
|
||||
.filter((a) => findTag(a, "status") === StreamState.Planned)
|
||||
.sort(sortStarts);
|
||||
const ended = feedSorted
|
||||
.filter((a) => {
|
||||
const hasEnded = findTag(a, "status") === StreamState.Ended;
|
||||
const recording = findTag(a, "recording") ?? "";
|
||||
return hasEnded && recording?.length > 0;
|
||||
})
|
||||
.sort(sortCreatedAt);
|
||||
|
||||
return { live, planned, ended };
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export enum LoginType {
|
||||
}
|
||||
|
||||
interface ReplaceableTags {
|
||||
tags: Array<string[]>;
|
||||
tags: Tags;
|
||||
content?: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
Reference in New Issue
Block a user