fix: mute buttons

closes #748
This commit is contained in:
kieran 2024-09-09 14:27:59 +01:00
parent c515e9837d
commit f2319b074f
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
7 changed files with 47 additions and 27 deletions

View File

@ -1,24 +1,23 @@
import { HexKey } from "@snort/system";
import { FormattedMessage } from "react-intl";
import useModeration from "@/Hooks/useModeration";
import messages from "../messages";
import AsyncButton from "../Button/AsyncButton";
interface MuteButtonProps {
pubkey: HexKey;
pubkey: string;
}
const MuteButton = ({ pubkey }: MuteButtonProps) => {
const { mute, unmute, isMuted } = useModeration();
return isMuted(pubkey) ? (
<button className="secondary" type="button" onClick={() => unmute(pubkey)}>
<FormattedMessage {...messages.Unmute} />
</button>
<AsyncButton className="secondary" type="button" onClick={() => unmute(pubkey)}>
<FormattedMessage defaultMessage="Unmute" />
</AsyncButton>
) : (
<button type="button" onClick={() => mute(pubkey)}>
<FormattedMessage {...messages.Mute} />
</button>
<AsyncButton type="button" onClick={() => mute(pubkey)}>
<FormattedMessage defaultMessage="Mute" />
</AsyncButton>
);
};

View File

@ -4,7 +4,10 @@ import { EventKind, NostrEvent, NostrLink, TaggedNostrEvent, ToNostrEventTag, Un
import useLogin from "@/Hooks/useLogin";
export class MutedWordTag implements ToNostrEventTag {
constructor(readonly word: string) {}
constructor(readonly word: string) { }
equals(other: ToNostrEventTag): boolean {
return other instanceof MutedWordTag && other.word === this.word;
}
toEventTag(): string[] | undefined {
return ["word", this.word.toLowerCase()];
@ -16,7 +19,7 @@ export default function useModeration() {
function isMuted(id: string) {
const link = NostrLink.publicKey(id);
return state.muted.includes(link);
return state.muted.some(a => a.equals(link));
}
async function unmute(id: string) {

View File

@ -15,9 +15,11 @@ import Avatar from "@/Components/User/Avatar";
import FollowButton from "@/Components/User/FollowButton";
import ProfileImage from "@/Components/User/ProfileImage";
import ZapModal from "@/Components/ZapModal/ZapModal";
import useModeration from "@/Hooks/useModeration";
import { hexToBech32 } from "@/Utils";
import { LoginSessionType, LoginStore } from "@/Utils/Login";
import { ZapTarget } from "@/Utils/Zapper";
import MuteButton from "@/Components/User/MuteButton";
const AvatarSection = ({
user,
@ -36,11 +38,14 @@ const AvatarSection = ({
const [modalImage, setModalImage] = useState<string>("");
const [showLnQr, setShowLnQr] = useState<boolean>(false);
const [prefix, setPrefix] = useState<NostrPrefix>(CONFIG.profileLinkPrefix);
const { mute, unmute, isMuted } = useModeration();
const navigate = useNavigate();
const relays = UserRelays.getFromCache(id);
const isMe = loginPubKey === id;
const canWrite = !!loginPubKey && !readonly;
const intl = useIntl();
const muted = id ? isMuted(id) : false;
const profileId = useMemo(() => {
if (!id) return;
@ -107,6 +112,19 @@ const AvatarSection = ({
icon={{ name: "envelope", size: 16 }}
/>
)}
{canWrite && muted && <MuteButton pubkey={id} />}
{canWrite && !muted && <IconButton
className={muted ? "bg-success" : "!bg-error"}
onClick={async () => {
if (muted) {
await unmute(id);
} else {
await mute(id);
}
}}
icon={{ name: "mute", size: 16 }}
/>
}
{!canWrite && !isMe && (
<IconButton
onClick={() => {

View File

@ -59,15 +59,6 @@ const ProfileTabSelectors = {
),
value: ProfileTabType.MUTED,
},
Blocked: {
text: (
<>
<Icon name="block" size={16} />
<FormattedMessage defaultMessage="Blocked" />
</>
),
value: ProfileTabType.BLOCKED,
},
Relays: {
text: (
<>

View File

@ -16,6 +16,8 @@ module.exports = {
"nostr-red": "var(--heart)",
"nostr-purple": "var(--highlight)",
secondary: "var(--font-secondary-color)",
"warning": "var(--warning)",
"error": "var(--error)"
},
spacing: {
px: "1px",

View File

@ -101,11 +101,7 @@ export class DiffSyncTags extends EventEmitter<SafeSyncEvents> {
async sync(signer: EventSigner | undefined, system: SystemInterface) {
await this.#sync.sync(system);
if (this.#sync.value?.content && this.contentEncrypted && signer) {
const decrypted = await signer.nip4Decrypt(this.#sync.value.content, await signer.getPubKey());
this.#decryptedContent = decrypted;
}
await this.#afterSync(signer);
}
/**
@ -123,6 +119,15 @@ export class DiffSyncTags extends EventEmitter<SafeSyncEvents> {
next.content = await signer.nip4Encrypt(next.content, await signer.getPubKey());
}
await this.#sync.update(next, signer, system, !isNew);
await this.#afterSync(signer);
}
async #afterSync(signer: EventSigner | undefined) {
if (this.#sync.value?.content && this.contentEncrypted && signer) {
const decrypted = await signer.nip4Decrypt(this.#sync.value.content, await signer.getPubKey());
this.#decryptedContent = decrypted;
this.emit("change");
}
}
#nextEvent(content?: string): NotSignedNostrEvent {
@ -141,6 +146,7 @@ export class DiffSyncTags extends EventEmitter<SafeSyncEvents> {
// apply changes onto next
next.tags = this.#applyChanges(next.tags, this.#changes);
if (this.#changesEncrypted.length > 0 && !content) {
debugger;
const encryptedTags = this.#applyChanges(isNew ? [] : this.encryptedTags, this.#changesEncrypted);
next.content = JSON.stringify(encryptedTags);
} else if (content) {

View File

@ -117,12 +117,13 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
}
await Promise.all(tasks);
this.#log(
"Init results: profile=%O, contacts=%O, relays=%O, appdata=%O, lists=%O",
"Init results: signer=%s, profile=%O, contacts=%O, relays=%O, appdata=%O, lists=%O",
signer ? "yes" : "no",
this.#profile.json,
this.#contacts.value,
this.#relays.value,
this.#appdata?.json,
[...this.#standardLists.values()].map(a => a.value),
[...this.#standardLists.values()].map(a => [a.value, a.encryptedTags]),
);
// update relay metadata with value from contact list if not found