From bb855a2f8f1be70d1b1f739ed229bcd09b73f931 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Fri, 11 Oct 2024 14:34:55 +0100 Subject: [PATCH] make app settings use query store --- pnpm-lock.yaml | 37 +--------- src/classes/accounts/account.ts | 4 +- .../embed-event/event-types/embedded-note.tsx | 4 +- .../event-types/embedded-torrent-comment.tsx | 5 +- src/components/event-zap-modal/index.tsx | 6 +- src/components/event-zap-modal/pay-step.tsx | 9 ++- .../external-embeds/types/music.tsx | 13 ++-- .../external-embeds/types/reddit.tsx | 14 ++-- .../external-embeds/types/twitter.tsx | 12 ++-- .../external-embeds/types/youtube.tsx | 46 +++++++----- src/components/note/timeline-note/index.tsx | 4 +- .../migrations.ts => helpers/app-settings.ts} | 4 +- src/helpers/image.ts | 18 ++++- src/helpers/request.ts | 20 +++++- src/hooks/use-app-settings.ts | 35 ++++++---- src/hooks/use-set-color-mode.ts | 5 +- src/providers/global/index.tsx | 48 +++++++------ src/providers/route/index.tsx | 2 +- ...e-modal.tsx => invoice-modal-provider.tsx} | 5 +- src/queries/app-settings.ts | 17 +++++ src/services/account.ts | 4 +- src/services/db/schema.ts | 2 +- src/services/settings/app-settings.ts | 47 ------------- src/services/settings/user-app-settings.ts | 50 ------------- src/services/user-app-settings.ts | 44 ++++++++++++ src/services/user-event-sync.ts | 70 ++++++++++++------- src/views/user/components/user-zap-button.tsx | 2 +- 27 files changed, 274 insertions(+), 253 deletions(-) rename src/{services/settings/migrations.ts => helpers/app-settings.ts} (96%) rename src/providers/route/{invoice-modal.tsx => invoice-modal-provider.tsx} (91%) create mode 100644 src/queries/app-settings.ts delete mode 100644 src/services/settings/app-settings.ts delete mode 100644 src/services/settings/user-app-settings.ts create mode 100644 src/services/user-app-settings.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae2c489dd..91c0ad20e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -94,13 +94,13 @@ importers: version: 0.6.0(typescript@5.6.2) applesauce-core: specifier: ^0.6.0 - version: 0.6.0(typescript@5.6.2) + version: link:../applesauce/packages/core applesauce-react: specifier: ^0.6.0 - version: 0.6.0(typescript@5.6.2) + version: link:../applesauce/packages/react applesauce-signer: specifier: ^0.6.0 - version: 0.6.0(typescript@5.6.2) + version: link:../applesauce/packages/signer bech32: specifier: ^2.0.0 version: 2.0.0 @@ -2703,14 +2703,6 @@ packages: resolution: { integrity: sha512-23W/7P0hzjVGIp51Yp4ppJgbDFNtrJrF3HO3/M36/z+Msdb3HKiSXmt3bMxEVMY6nJTT+zWneq7mAd7VvwhWaA== } - applesauce-react@0.6.0: - resolution: - { integrity: sha512-T8fd7ImkrSe0o+FjC5AoLsYeqlLWq5bE5evwavR2+NTLC9CW185qKPPIzbTDrakq4hPADV8by3AOCmD+MY1Riw== } - - applesauce-signer@0.6.0: - resolution: - { integrity: sha512-BunnObvSqIBJ04MMQnpXIflfYEAwqWROCJqQrFZXHy+yXmZjHzPVMkXQLcJ7oXoNVc4CaxgJwp7w8eSmohJKFg== } - argparse@1.0.10: resolution: { integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== } @@ -8301,29 +8293,6 @@ snapshots: - supports-color - typescript - applesauce-react@0.6.0(typescript@5.6.2): - dependencies: - applesauce-core: 0.6.0(typescript@5.6.2) - nostr-tools: 2.7.2(typescript@5.6.2) - react: 18.3.1 - zen-observable: 0.10.0 - transitivePeerDependencies: - - supports-color - - typescript - - applesauce-signer@0.6.0(typescript@5.6.2): - dependencies: - "@noble/hashes": 1.5.0 - "@noble/secp256k1": 1.7.1 - "@scure/base": 1.1.9 - "@types/dom-serial": 1.0.6 - applesauce-core: 0.6.0(typescript@5.6.2) - debug: 4.3.7 - nostr-tools: 2.7.2(typescript@5.6.2) - transitivePeerDependencies: - - supports-color - - typescript - argparse@1.0.10: dependencies: sprintf-js: 1.0.3 diff --git a/src/classes/accounts/account.ts b/src/classes/accounts/account.ts index 6c24b8265..c87a98c3a 100644 --- a/src/classes/accounts/account.ts +++ b/src/classes/accounts/account.ts @@ -1,10 +1,10 @@ -import { AppSettings } from "../../services/settings/migrations"; +import { AppSettings } from "../../helpers/app-settings"; import { Nip07Interface } from "applesauce-signer"; export class Account { readonly type: string = "unknown"; pubkey: string; - localSettings?: AppSettings; + localSettings?: Partial; protected _signer?: Nip07Interface | undefined; public get signer(): Nip07Interface | undefined { diff --git a/src/components/embed-event/event-types/embedded-note.tsx b/src/components/embed-event/event-types/embedded-note.tsx index e35b19955..7644f0a27 100644 --- a/src/components/embed-event/event-types/embedded-note.tsx +++ b/src/components/embed-event/event-types/embedded-note.tsx @@ -6,7 +6,6 @@ import { NostrEvent } from "../../../types/nostr-event"; import UserAvatarLink from "../../user/user-avatar-link"; import UserLink from "../../user/user-link"; import useSubject from "../../../hooks/use-subject"; -import appSettings from "../../../services/settings/app-settings"; import EventVerificationIcon from "../../common-event/event-verification-icon"; import { TrustProvider } from "../../../providers/local/trust-provider"; import { NoteLink } from "../../note/note-link"; @@ -17,9 +16,10 @@ import HoverLinkOverlay from "../../hover-link-overlay"; import singleEventService from "../../../services/single-event"; import relayHintService from "../../../services/event-relay-hint"; import localSettings from "../../../services/local-settings"; +import useAppSettings from "../../../hooks/use-app-settings"; export default function EmbeddedNote({ event, ...props }: Omit & { event: NostrEvent }) { - const { showSignatureVerification } = useSubject(appSettings); + const { showSignatureVerification } = useAppSettings(); const enableDrawer = useSubject(localSettings.enableNoteThreadDrawer); const navigate = enableDrawer ? useNavigateInDrawer() : useNavigate(); const to = `/n/${relayHintService.getSharableEventAddress(event)}`; diff --git a/src/components/embed-event/event-types/embedded-torrent-comment.tsx b/src/components/embed-event/event-types/embedded-torrent-comment.tsx index 8016cce3b..4efc0d243 100644 --- a/src/components/embed-event/event-types/embedded-torrent-comment.tsx +++ b/src/components/embed-event/event-types/embedded-torrent-comment.tsx @@ -4,8 +4,6 @@ import { Link as RouterLink } from "react-router-dom"; import { NostrEvent } from "../../../types/nostr-event"; import UserAvatarLink from "../../user/user-avatar-link"; import UserLink from "../../user/user-link"; -import useSubject from "../../../hooks/use-subject"; -import appSettings from "../../../services/settings/app-settings"; import EventVerificationIcon from "../../common-event/event-verification-icon"; import { TrustProvider } from "../../../providers/local/trust-provider"; import Timestamp from "../../timestamp"; @@ -17,13 +15,14 @@ import { getTorrentTitle } from "../../../helpers/nostr/torrents"; import { useNavigateInDrawer } from "../../../providers/drawer-sub-view-provider"; import { MouseEventHandler, useCallback } from "react"; import { nip19 } from "nostr-tools"; +import useAppSettings from "../../../hooks/use-app-settings"; export default function EmbeddedTorrentComment({ comment, ...props }: Omit & { comment: NostrEvent }) { const navigate = useNavigateInDrawer(); - const { showSignatureVerification } = useSubject(appSettings); + const { showSignatureVerification } = useAppSettings(); const refs = getThreadReferences(comment); const torrent = useSingleEvent(refs.root?.e?.id, refs.root?.e?.relays); const linkToTorrent = refs.root?.e && `/torrents/${nip19.neventEncode(refs.root.e)}`; diff --git a/src/components/event-zap-modal/index.tsx b/src/components/event-zap-modal/index.tsx index 46f8e213a..7466df490 100644 --- a/src/components/event-zap-modal/index.tsx +++ b/src/components/event-zap-modal/index.tsx @@ -21,13 +21,14 @@ import { EmbedProps } from "../embed-event"; import userMailboxesService from "../../services/user-mailboxes"; import InputStep from "./input-step"; import lnurlMetadataService from "../../services/lnurl-metadata"; -import userMetadataService from "../../services/user-metadata"; import signingService from "../../services/signing"; import accountService from "../../services/account"; import PayStep from "./pay-step"; import { getInvoiceFromCallbackUrl } from "../../helpers/lnurl"; import UserLink from "../user/user-link"; import relayHintService from "../../services/event-relay-hint"; +import { queryStore } from "../../services/event-store"; +import { getValue } from "applesauce-core/observable"; export type PayRequest = { invoice?: string; pubkey: string; error?: any }; @@ -38,7 +39,8 @@ async function getPayRequestForPubkey( comment?: string, additionalRelays?: Iterable, ): Promise { - const metadata = userMetadataService.getSubject(pubkey).value; + const metadata = await getValue(queryStore.profile(pubkey)); + if (!metadata) throw new Error("Cant find user metadata"); const address = metadata?.lud16 || metadata?.lud06; if (!address) throw new Error("User missing lightning address"); const lnurlMetadata = await lnurlMetadataService.requestMetadata(address); diff --git a/src/components/event-zap-modal/pay-step.tsx b/src/components/event-zap-modal/pay-step.tsx index 2434d3213..97a855988 100644 --- a/src/components/event-zap-modal/pay-step.tsx +++ b/src/components/event-zap-modal/pay-step.tsx @@ -7,7 +7,7 @@ import UserLink from "../user/user-link"; import { ChevronDownIcon, ChevronUpIcon, CheckIcon, ErrorIcon, LightningIcon } from "../icons"; import { InvoiceModalContent } from "../invoice-modal"; import { PropsWithChildren, useEffect, useState } from "react"; -import appSettings from "../../services/settings/app-settings"; +import useAppSettings from "../../hooks/use-app-settings"; function UserCard({ children, pubkey }: PropsWithChildren & { pubkey: string }) { return ( @@ -79,6 +79,7 @@ function ErrorCard({ pubkey, error }: { pubkey: string; error: any }) { export default function PayStep({ callbacks, onComplete }: { callbacks: PayRequest[]; onComplete: () => void }) { const [paid, setPaid] = useState([]); + const { autoPayWithWebLN } = useAppSettings(); const [payingAll, setPayingAll] = useState(false); const payAllWithWebLN = async () => { @@ -99,14 +100,16 @@ export default function PayStep({ callbacks, onComplete }: { callbacks: PayReque }; useEffect(() => { - if (!callbacks.filter((p) => !!p.invoice).some(({ pubkey }) => !paid.includes(pubkey))) { + const withInvoice = callbacks.filter((p) => !!p.invoice); + const hasUnpaid = withInvoice.some(({ pubkey }) => !paid.includes(pubkey)); + if (withInvoice.length > 0 && !hasUnpaid) { onComplete(); } }, [paid]); // if autoPayWithWebLN is enabled, try to pay all immediately useMount(() => { - if (appSettings.value.autoPayWithWebLN) { + if (autoPayWithWebLN) { payAllWithWebLN(); } }); diff --git a/src/components/external-embeds/types/music.tsx b/src/components/external-embeds/types/music.tsx index 6e197b2cb..804dd38ff 100644 --- a/src/components/external-embeds/types/music.tsx +++ b/src/components/external-embeds/types/music.tsx @@ -1,9 +1,9 @@ import { CSSProperties } from "react"; import { Box, useColorMode } from "@chakra-ui/react"; import { EmbedEventPointer } from "../../embed-event"; -import appSettings from "../../../services/settings/app-settings"; import { STEMSTR_RELAY } from "../../../helpers/nostr/stemstr"; import ExpandableEmbed from "../expandable-embed"; +import useAppSettings from "../../../hooks/use-app-settings"; const setZIndex: CSSProperties = { zIndex: 1, position: "relative" }; @@ -137,8 +137,8 @@ export function renderStemstrUrl(match: URL) { return ; } -export function renderSoundCloudUrl(match: URL) { - if (match.hostname !== "soundcloud.com" || match.pathname.split("/").length !== 3) return null; +function SoundCloudEmbed({ match }: { match: URL }) { + const { primaryColor } = useAppSettings(); return ( ); } +export function renderSoundCloudUrl(match: URL) { + if (match.hostname !== "soundcloud.com" || match.pathname.split("/").length !== 3) return null; + + return ; +} diff --git a/src/components/external-embeds/types/reddit.tsx b/src/components/external-embeds/types/reddit.tsx index 79a7788b6..4d542fe2f 100644 --- a/src/components/external-embeds/types/reddit.tsx +++ b/src/components/external-embeds/types/reddit.tsx @@ -1,5 +1,5 @@ import { replaceDomain } from "../../../helpers/url"; -import appSettings from "../../../services/settings/app-settings"; +import useAppSettings from "../../../hooks/use-app-settings"; import { renderGenericUrl } from "./common"; // copied from https://github.com/SimonBrazell/privacy-redirect/blob/master/src/assets/javascripts/helpers/reddit.js @@ -13,13 +13,17 @@ const REDDIT_DOMAINS = [ "old.reddit.com", ]; +function RedditLink({ url }: { url: URL }) { + const { redditRedirect } = useAppSettings(); + const fixed = redditRedirect ? replaceDomain(url, redditRedirect) : url; + + return renderGenericUrl(fixed); +} + const bypassPaths = /\/(gallery\/poll\/rpan\/settings\/topics)/; export function renderRedditUrl(match: URL) { if (!REDDIT_DOMAINS.includes(match.hostname)) return null; if (match.pathname.match(bypassPaths)) return null; - const { redditRedirect } = appSettings.value; - const fixed = redditRedirect ? replaceDomain(match, redditRedirect) : match; - - return renderGenericUrl(fixed); + return ; } diff --git a/src/components/external-embeds/types/twitter.tsx b/src/components/external-embeds/types/twitter.tsx index 81e0ba582..3b4e7d3a9 100644 --- a/src/components/external-embeds/types/twitter.tsx +++ b/src/components/external-embeds/types/twitter.tsx @@ -1,14 +1,18 @@ import { replaceDomain } from "../../../helpers/url"; -import appSettings from "../../../services/settings/app-settings"; +import useAppSettings from "../../../hooks/use-app-settings"; import { renderOpenGraphUrl } from "./common"; // copied from https://github.com/SimonBrazell/privacy-redirect/blob/master/src/assets/javascripts/helpers/twitter.js export const TWITTER_DOMAINS = ["x.com", "twitter.com", "www.twitter.com", "mobile.twitter.com", "pbs.twimg.com"]; +function TwitterLink({ url, isLineEnd }: { url: URL; isLineEnd?: boolean }) { + const { twitterRedirect } = useAppSettings(); + if (twitterRedirect) return renderOpenGraphUrl(replaceDomain(url, twitterRedirect), !!isLineEnd); + else return renderOpenGraphUrl(url, !!isLineEnd); +} + export function renderTwitterUrl(match: URL, isLineEnd: boolean) { if (!TWITTER_DOMAINS.includes(match.hostname)) return null; - const { twitterRedirect } = appSettings.value; - if (twitterRedirect) return renderOpenGraphUrl(replaceDomain(match, twitterRedirect), isLineEnd); - else return renderOpenGraphUrl(match, isLineEnd); + return ; } diff --git a/src/components/external-embeds/types/youtube.tsx b/src/components/external-embeds/types/youtube.tsx index 480533871..4ab5466c8 100644 --- a/src/components/external-embeds/types/youtube.tsx +++ b/src/components/external-embeds/types/youtube.tsx @@ -1,6 +1,6 @@ import { AspectRatio } from "@chakra-ui/react"; -import appSettings from "../../../services/settings/app-settings"; import ExpandableEmbed from "../expandable-embed"; +import useAppSettings from "../../../hooks/use-app-settings"; // copied from https://github.com/SimonBrazell/privacy-redirect/blob/master/src/assets/javascripts/helpers/youtube.js export const YOUTUBE_DOMAINS = [ @@ -15,20 +15,15 @@ export const YOUTUBE_DOMAINS = [ "music.youtube.com", ]; -export function renderYoutubePlaylistURL(match: URL) { - if (!YOUTUBE_DOMAINS.includes(match.hostname)) return null; - if (!match.pathname.startsWith("/playlist")) return null; - - const { youtubeRedirect } = appSettings.value; - - const listId = match.searchParams.get("list"); - if (!listId) return null; +function YoutubePlaylistEmbed({ url }: { url: URL }) { + const { youtubeRedirect } = useAppSettings(); + const listId = url.searchParams.get("list")!; const embedUrl = new URL(`embed/videoseries`, youtubeRedirect || "https://www.youtube-nocookie.com"); embedUrl.searchParams.set("list", listId); return ( - +