From 993a0ea6d58e50e9bec14811163002ac6a2cec94 Mon Sep 17 00:00:00 2001 From: Jason Efstathiou Date: Mon, 16 Oct 2023 11:48:19 +0200 Subject: [PATCH 1/2] fix: #732 (#733) --- .../methods/delete-stream.ts | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/lib/flows/delete-stream-flow/methods/delete-stream.ts b/src/lib/flows/delete-stream-flow/methods/delete-stream.ts index 0b50e8857..a68b62db5 100644 --- a/src/lib/flows/delete-stream-flow/methods/delete-stream.ts +++ b/src/lib/flows/delete-stream-flow/methods/delete-stream.ts @@ -37,19 +37,22 @@ export default function ( assert(assetConfig, "App hasnʼt yet fetched user's own account"); const metadataMgr = new AddressDriverMetadataManager(); - const metadata = metadataMgr.buildAccountMetadata({ forAccount: ownAccount, address }); - const assetConfigIndex = metadata.assetConfigs.findIndex( - (mac) => mac.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(), - ); - const streamIndex = metadata.assetConfigs[assetConfigIndex].streams.findIndex( - (ms) => ms.id === stream.id, - ); - metadata.assetConfigs[assetConfigIndex].streams.splice(streamIndex, 1); + // If the stream isn't managed, it didn't have any metadata, so we don't need to make any changes to it. + if (stream.managed) { + const assetConfigIndex = metadata.assetConfigs.findIndex( + (mac) => mac.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(), + ); + const streamIndex = metadata.assetConfigs[assetConfigIndex].streams.findIndex( + (ms) => ms.id === stream.id, + ); - if (metadata.assetConfigs[assetConfigIndex].streams.length === 0) { - metadata.assetConfigs.splice(assetConfigIndex, 1); + metadata.assetConfigs[assetConfigIndex].streams.splice(streamIndex, 1); + + if (metadata.assetConfigs[assetConfigIndex].streams.length === 0) { + metadata.assetConfigs.splice(assetConfigIndex, 1); + } } const newHash = await metadataMgr.pinAccountMetadata(metadata); @@ -71,6 +74,10 @@ export default function ( const { ADDRESS_DRIVER } = getNetworkConfig(); + /* + Pretty confusing that this is a "createStream" preset, but all it is does is 1) call setStreams, and + 2) update metadata. Since we need to do exactly this also for deleting streams, we can use it here. + */ const createStreamBatchPreset = await AddressDriverPresets.Presets.createNewStreamFlow({ signer, driverAddress: ADDRESS_DRIVER, @@ -102,9 +109,9 @@ export default function ( after: async (_, transactContext) => { /* - We wait up to five seconds for `refreshUserAccount` to update the user's own - account's `lastIpfsHash` to the new hash we just published. - */ + We wait up to five seconds for `refreshUserAccount` to update the user's own + account's `lastIpfsHash` to the new hash we just published. + */ await expect( streams.refreshUserAccount, () => From 941ae61156194681c0a2c156553c34fbdceedc8d Mon Sep 17 00:00:00 2001 From: Jason Efstathiou Date: Mon, 16 Oct 2023 13:05:36 +0200 Subject: [PATCH 2/2] feat: jump to drip list by ID in search (#734) --- src/lib/components/head-meta/head-meta.svelte | 6 +- .../search-bar/components/result.svelte | 2 +- src/lib/utils/decode-universal-account-id.ts | 99 +++++++++++++++++++ src/lib/utils/decode-user-id.ts | 59 ----------- src/routes/app/(app)/[accountId]/+page.svelte | 44 ++++++--- .../[accountId]/tokens/[token]/+page.svelte | 2 +- .../[token]/streams/[dripId]/+page.svelte | 2 +- .../(app)/drip-lists/[listId]/+page.svelte | 4 +- 8 files changed, 142 insertions(+), 76 deletions(-) create mode 100644 src/lib/utils/decode-universal-account-id.ts delete mode 100644 src/lib/utils/decode-user-id.ts diff --git a/src/lib/components/head-meta/head-meta.svelte b/src/lib/components/head-meta/head-meta.svelte index e9c8c2d71..29472605a 100644 --- a/src/lib/components/head-meta/head-meta.svelte +++ b/src/lib/components/head-meta/head-meta.svelte @@ -9,9 +9,11 @@ - {title}{title.startsWith('Drips') ? '' : ' | Drips'} + {#if title} + {title}{title.startsWith('Drips') ? '' : ' | Drips'} + + {/if} - diff --git a/src/lib/components/search-bar/components/result.svelte b/src/lib/components/search-bar/components/result.svelte index 538f57bab..f24ae2220 100644 --- a/src/lib/components/search-bar/components/result.svelte +++ b/src/lib/components/search-bar/components/result.svelte @@ -72,7 +72,7 @@
{#if !item.item.name && !item.item.address && item.item.dripsAccountId} - Jump to user ID: + Jump to account ID: {/if} {@html highlighted} diff --git a/src/lib/utils/decode-universal-account-id.ts b/src/lib/utils/decode-universal-account-id.ts new file mode 100644 index 000000000..781d7570e --- /dev/null +++ b/src/lib/utils/decode-universal-account-id.ts @@ -0,0 +1,99 @@ +import ens from '$lib/stores/ens'; +import { getAddressDriverClient } from '$lib/utils/get-drips-clients'; +import { isAddress } from 'ethers/lib/utils'; +import { AddressDriverClient, Utils } from 'radicle-drips'; +import { get } from 'svelte/store'; + +interface AddressDriverResult { + driver: 'address'; + address: string; + dripsAccountId: string; +} + +interface RepoDriverResult { + driver: 'repo'; + dripsAccountId: string; +} + +interface NFTDriverResult { + driver: 'nft'; + dripsAccountId: string; +} + +/** + * "universalAcccountIdentifier" is either an .ens name, an ETH address, or a Drips User ID (any supported driver). + * This utility takes such an identifier (which e.g. may be navigated to via drips.network/), + * figures out which of the options it is, and returns an object describing the target. + * @param universalAcccountIdentifier + */ +export default async function ( + universalAcccountIdentifier: string, +): Promise { + if (isAddress(universalAcccountIdentifier)) { + const address = universalAcccountIdentifier; + const dripsAccountId = await ( + await getAddressDriverClient() + ).getAccountIdByAddress(universalAcccountIdentifier); + + return { + driver: 'address', + address, + dripsAccountId, + }; + } else if (universalAcccountIdentifier.endsWith('.eth')) { + // Subscribe to ens.connected store and wait until it's true + + const ensConnected = ens.connected; + + if (!get(ensConnected)) { + await new Promise((resolve) => { + const unsubscribe = ensConnected.subscribe((connected) => { + if (connected) { + unsubscribe(); + resolve(undefined); + } + }); + }); + } + + const lookup = await ens.reverseLookup(universalAcccountIdentifier); + if (lookup) { + const dripsAccountId = await (await getAddressDriverClient()).getAccountIdByAddress(lookup); + const address = lookup; + + return { + driver: 'address', + address, + dripsAccountId, + }; + } else { + throw new Error('Not found'); + } + } else if (/^\d+$/.test(universalAcccountIdentifier)) { + // User ID param has only numbers and is probably a drips user ID + const dripsAccountId = universalAcccountIdentifier; + + const driver = Utils.AccountId.getDriver(dripsAccountId); + + if (driver === 'address') { + const address = AddressDriverClient.getUserAddress(universalAcccountIdentifier); + + return { + driver: 'address', + address, + dripsAccountId, + }; + } else { + if (driver === 'immutableSplits') { + throw new Error('Unsupported Driver'); + } + + return { + driver, + dripsAccountId, + }; + } + } else { + throw new Error('Not found.'); + } +} diff --git a/src/lib/utils/decode-user-id.ts b/src/lib/utils/decode-user-id.ts deleted file mode 100644 index 37b1cb882..000000000 --- a/src/lib/utils/decode-user-id.ts +++ /dev/null @@ -1,59 +0,0 @@ -import ens from '$lib/stores/ens'; -import { getAddressDriverClient } from '$lib/utils/get-drips-clients'; -import { isAddress } from 'ethers/lib/utils'; -import { AddressDriverClient } from 'radicle-drips'; -import { get } from 'svelte/store'; - -export default async function (accountId: string): Promise<{ - address: string; - dripsAccountId: string; -}> { - if (isAddress(accountId)) { - const address = accountId; - const dripsAccountId = await (await getAddressDriverClient()).getAccountIdByAddress(accountId); - - return { - address, - dripsAccountId, - }; - } else if (/^\d+$/.test(accountId)) { - // User ID param has only numbers and is probably a drips user ID - const dripsAccountId = accountId; - const address = AddressDriverClient.getUserAddress(accountId); - - return { - address, - dripsAccountId, - }; - } else if (accountId.endsWith('.eth')) { - // Subscribe to ens.connected store and wait until it's true - - const ensConnected = ens.connected; - - if (!get(ensConnected)) { - await new Promise((resolve) => { - const unsubscribe = ensConnected.subscribe((connected) => { - if (connected) { - unsubscribe(); - resolve(undefined); - } - }); - }); - } - - const lookup = await ens.reverseLookup(accountId); - if (lookup) { - const dripsAccountId = await (await getAddressDriverClient()).getAccountIdByAddress(lookup); - const address = lookup; - - return { - address, - dripsAccountId, - }; - } else { - throw new Error('Not found'); - } - } else { - throw new Error('Not found.'); - } -} diff --git a/src/routes/app/(app)/[accountId]/+page.svelte b/src/routes/app/(app)/[accountId]/+page.svelte index 850018479..ed3332e0d 100644 --- a/src/routes/app/(app)/[accountId]/+page.svelte +++ b/src/routes/app/(app)/[accountId]/+page.svelte @@ -12,7 +12,7 @@ import unreachable from '$lib/utils/unreachable'; import SectionSkeleton from '$lib/components/section-skeleton/section-skeleton.svelte'; import { fade, fly } from 'svelte/transition'; - import decodeAccountId from '$lib/utils/decode-user-id'; + import decodeUniversalAccountId from '$lib/utils/decode-universal-account-id'; import dismissablesStore from '$lib/stores/dismissables/dismissables.store'; import DripsV1Logo from '$lib/components/illustrations/drips-v1-logo.svelte'; import Banner from '$lib/components/banner/banner.svelte'; @@ -20,12 +20,13 @@ import ProjectsSection from '$lib/components/projects-section/projects-section.svelte'; import DripListsSection from '$lib/components/drip-lists-section/drip-lists-section.svelte'; import Developer from '$lib/components/developer-section/developer.section.svelte'; + import { goto } from '$app/navigation'; $: accountId = $page.params.accountId; let dripsAccountId: string | undefined; let address: string | undefined; - let error: Error | undefined; + let error: 'is-repo-driver-account-id' | true | undefined; const ensRecords = ['description', 'url', 'com.twitter', 'com.github'] as const; const socialLinks = ['com.twitter', 'com.github', 'url'] as const; @@ -70,12 +71,27 @@ onMount(async () => { try { - const decodedAccountId = await decodeAccountId(accountId); - - address = decodedAccountId.address; - dripsAccountId = decodedAccountId.dripsAccountId; + const decodedAccountId = await decodeUniversalAccountId(accountId); + + switch (decodedAccountId.driver) { + case 'address': { + address = decodedAccountId.address; + dripsAccountId = decodedAccountId.dripsAccountId; + break; + } + case 'nft': { + goto(`/app/drip-lists/${decodedAccountId.dripsAccountId}`); + break; + } + case 'repo': { + error = 'is-repo-driver-account-id'; + break; + } + } } catch (e) { - error = e instanceof Error ? e : new Error(); + // eslint-disable-next-line no-console + console.error(e); + error = true; } }); @@ -94,7 +110,7 @@ } catch (e) { // eslint-disable-next-line no-console console.error(e); - error = e instanceof Error ? e : new Error('Unable to fetch account'); + error = true; } } @@ -107,11 +123,17 @@ -{#if error} +{#if error === 'is-repo-driver-account-id'} + +{:else if error} {:else}
diff --git a/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte b/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte index 21b0eff4f..189a4152e 100644 --- a/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte +++ b/src/routes/app/(app)/[accountId]/tokens/[token]/+page.svelte @@ -15,7 +15,7 @@ import wallet from '$lib/stores/wallet/wallet.store'; import guardConnected from '$lib/utils/guard-connected'; import checkIsUser from '$lib/utils/check-is-user'; - import decodeAccountId from '$lib/utils/decode-user-id'; + import decodeAccountId from '$lib/utils/decode-universal-account-id'; import LargeEmptyState from '$lib/components/large-empty-state/large-empty-state.svelte'; import collectFlowSteps from '$lib/flows/collect-flow/collect-flow-steps'; import getWithdrawSteps from '$lib/flows/withdraw-flow/withdraw-flow-steps'; diff --git a/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte b/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte index 2130d4df7..8d35e16e0 100644 --- a/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte +++ b/src/routes/app/(app)/[accountId]/tokens/[token]/streams/[dripId]/+page.svelte @@ -9,7 +9,7 @@ import Spinner from '$lib/components/spinner/spinner.svelte'; import StreamVisual from '$lib/components/stream-visual/stream-visual.svelte'; import balances from '$lib/stores/balances'; - import decodeAccountId from '$lib/utils/decode-user-id'; + import decodeAccountId from '$lib/utils/decode-universal-account-id'; import unreachable from '$lib/utils/unreachable'; import FormattedAmount from '$lib/components/formatted-amount/formatted-amount.svelte'; import tokens from '$lib/stores/tokens'; diff --git a/src/routes/app/(app)/drip-lists/[listId]/+page.svelte b/src/routes/app/(app)/drip-lists/[listId]/+page.svelte index 08af40b16..27a1200bb 100644 --- a/src/routes/app/(app)/drip-lists/[listId]/+page.svelte +++ b/src/routes/app/(app)/drip-lists/[listId]/+page.svelte @@ -24,7 +24,9 @@ $: streamsFetched = $streamsFetchStatusses[ownerAccountId] === 'fetched'; - +{#if data.dripList.name} + +{/if}