From caf893d7877f1ee768da52d0644d3b723192c042 Mon Sep 17 00:00:00 2001 From: Georgios Jason Efstathiou Date: Mon, 2 Oct 2023 17:13:39 +0200 Subject: [PATCH] feat: aligned copy around earnings, even simpler collect modal --- .../flows/collect-flow/collect-amounts.svelte | 115 +++++++----------- .../flows/collect-flow/collect-flow-state.ts | 13 +- .../fetch-collectable-amounts.svelte | 2 +- src/lib/utils/format-date.ts | 19 ++- src/routes/app/(app)/projects/+page.svelte | 4 +- 5 files changed, 68 insertions(+), 85 deletions(-) diff --git a/src/lib/flows/collect-flow/collect-amounts.svelte b/src/lib/flows/collect-flow/collect-amounts.svelte index 52a1f3583..666bf960b 100644 --- a/src/lib/flows/collect-flow/collect-amounts.svelte +++ b/src/lib/flows/collect-flow/collect-amounts.svelte @@ -32,14 +32,12 @@ import expect from '$lib/utils/expect'; import transact, { makeTransactPayload } from '$lib/components/stepper/utils/transact'; import type { StepComponentEvents } from '$lib/components/stepper/types'; - import { createEventDispatcher } from 'svelte'; + import { createEventDispatcher, onMount } from 'svelte'; import SafeAppDisclaimer from '$lib/components/safe-app-disclaimer/safe-app-disclaimer.svelte'; import type { AddressDriverAccount } from '$lib/stores/streams/types'; export let context: Writable; - const restorer = $context.restorer; - $: cycle = $context.currentDripsCycle ?? unreachable(); $: currentCycleEnd = new Date(cycle.start.getTime() + cycle.durationMillis); @@ -86,6 +84,15 @@ return acc; }, []); + // Initially select all incoming squeeze senders by default, unless there's prior state. + onMount(() => { + if ($context.selectedSqueezeSenderItems?.length === 0 && !$context.squeezeEnabled) { + $context.selectedSqueezeSenderItems = incomingEstimatesBySender.map( + (e) => e.sender.accountId, + ); + } + }); + let currentCycleSenders: Items; $: currentCycleSenders = Object.fromEntries( mapFilterUndefined(incomingEstimatesBySender, (estimate) => { @@ -110,11 +117,8 @@ }), ); - let squeezeEnabled = restorer.restore('squeezeEnabled'); - let selectedSqueezeSenderItems: string[] = restorer.restore('selectedSqueezeSenderItems'); - - $: totalSelectedSqueezeAmount = squeezeEnabled - ? selectedSqueezeSenderItems.reduce( + $: totalSelectedSqueezeAmount = $context.squeezeEnabled + ? $context.selectedSqueezeSenderItems.reduce( (acc, sender) => acc + (incomingEstimatesBySender.find((e) => e.sender.accountId === sender)?.amount ?? @@ -145,8 +149,8 @@ const { DRIPS, ADDRESS_DRIVER } = getNetworkConfig(); let squeezeArgs: Awaited> | undefined; - if (squeezeEnabled && selectedSqueezeSenderItems.length > 0) { - squeezeArgs = await getSqueezeArgs(selectedSqueezeSenderItems, tokenAddress); + if ($context.squeezeEnabled && $context.selectedSqueezeSenderItems.length > 0) { + squeezeArgs = await getSqueezeArgs($context.selectedSqueezeSenderItems, tokenAddress); } const collectFlow = await AddressDriverPresets.Presets.createCollectFlow({ @@ -201,22 +205,18 @@ context.update((c) => ({ ...c, amountCollected, - squeezeEnabled, receipt, })); // The squeeze event should be indexed by now, so this should cause the dashboard to update // in the background to reflect the newly reduced incoming balance. - if (squeezeEnabled) await balancesStore.updateSqueezeHistory(transactContext.accountId); + if ($context.squeezeEnabled) { + await balancesStore.updateSqueezeHistory(transactContext.accountId); + } }, }), ); } - - $: restorer.saveAll({ - squeezeEnabled, - selectedSqueezeSenderItems, - }); @@ -224,35 +224,25 @@

- Income from Drip Lists, projects, and streams settles once per week. Your collectable balance - updates next on {formatDate(currentCycleEnd, 'onlyDay')}. + Earnings settle once per week. The next settlement date is {formatDate(currentCycleEnd, 'onlyDay')}.

- Learn more
{#if incomingEstimatesBySender.length > 0}
- -

- You may collect stream income from specific senders already before it settles, but the - network fee for collecting increases with each selected sender. -

+ - The amounts shown below are estimated based on your system time so the value you collect - may slightly differ. + The network fee for collecting increases with each selected sender. Unsettled earnings are + estimates, so you may collect less than expected.
@@ -262,36 +252,29 @@ 0n ? { - title: `Settled ${selectedToken.symbol}`, - subtitle: 'From incoming streams', - value: formatTokenAmount( - makeAmount(balances.receivable), - selectedToken.decimals, - 1n, - ), + title: `Streams`, + subtitle: $context.squeezeEnabled ? 'Including unsettled earnings' : undefined, + value: + $context.squeezeEnabled && totalSelectedSqueezeAmount > 0n + ? '≈ ' + + formatTokenAmount( + makeAmount(balances.receivable + (totalSelectedSqueezeAmount ?? 0n)), + selectedToken.decimals, + 1n, + ) + : formatTokenAmount( + makeAmount(balances.receivable), + selectedToken.decimals, + 1n, + ), symbol: selectedToken.symbol, } : undefined, balances.splittable > 0n ? { - title: `Settled ${selectedToken.symbol}`, - subtitle: 'From Drip Lists and projects', + title: 'Drip Lists and projects', value: formatTokenAmount( makeAmount(balances.splittable), selectedToken.decimals, @@ -311,7 +294,7 @@ ? { title: `Splitting ${getSplitPercent(1000000n - ownSplitsWeight, 'pretty')}`, value: - (squeezeEnabled ? '≈ ' : '') + + ($context.squeezeEnabled ? '≈ ' : '') + formatTokenAmount( makeAmount(collectableAfterSplit - splittableAfterReceive), selectedToken.decimals, @@ -338,7 +321,7 @@ title: 'You collect', subtitle: 'These funds will be sent to your wallet.', value: - (squeezeEnabled ? '≈ ' : '') + + ($context.squeezeEnabled && totalSelectedSqueezeAmount > 0n ? '≈ ' : '') + formatTokenAmount(makeAmount(collectableAfterSplit), selectedToken.decimals, 1n), symbol: selectedToken.symbol, disabled: collectableAfterSplit === 0n, @@ -365,18 +348,6 @@ text-align: left; } - .squeeze-section p { - margin-bottom: 1rem; - } - - a { - color: var(--color-foreground-level-6); - text-decoration: underline; - display: block; - margin-top: 0.5rem; - text-align: left; - } - .list-wrapper { margin-top: 1rem; border: 1px solid var(--color-foreground); diff --git a/src/lib/flows/collect-flow/collect-flow-state.ts b/src/lib/flows/collect-flow/collect-flow-state.ts index 4b56bd4a7..12b83f322 100644 --- a/src/lib/flows/collect-flow/collect-flow-state.ts +++ b/src/lib/flows/collect-flow/collect-flow-state.ts @@ -1,13 +1,7 @@ -import { newRestorer, type Restorer } from '$lib/utils/restorer'; import type { ContractReceipt } from 'ethers'; import type { SplitsEntry } from 'radicle-drips'; import { writable } from 'svelte/store'; -type Restorable = { - squeezeEnabled: boolean; - selectedSqueezeSenderItems: string[]; -}; - export interface CollectFlowState { tokenAddress?: string; balances?: { @@ -23,13 +17,14 @@ export interface CollectFlowState { durationMillis: number; }; amountCollected?: bigint; - squeezeEnabled?: boolean; + squeezeEnabled: boolean; + selectedSqueezeSenderItems: string[]; receipt?: ContractReceipt; - restorer: Restorer; } export default (tokenAddress?: string) => writable({ tokenAddress, - restorer: newRestorer({ squeezeEnabled: false, selectedSqueezeSenderItems: [] }), + squeezeEnabled: false, + selectedSqueezeSenderItems: [], }); diff --git a/src/lib/flows/collect-flow/fetch-collectable-amounts.svelte b/src/lib/flows/collect-flow/fetch-collectable-amounts.svelte index e4ee11bf6..2a53c7cb8 100644 --- a/src/lib/flows/collect-flow/fetch-collectable-amounts.svelte +++ b/src/lib/flows/collect-flow/fetch-collectable-amounts.svelte @@ -80,7 +80,7 @@ onMount(() => dispatch('await', { promise, - message: 'Fetching collectable amounts…', + message: 'Getting ready…', }), ); diff --git a/src/lib/utils/format-date.ts b/src/lib/utils/format-date.ts index 25fc19308..cf2ca6dab 100644 --- a/src/lib/utils/format-date.ts +++ b/src/lib/utils/format-date.ts @@ -23,6 +23,20 @@ const DATE_FORMAT_CONVENTIONS = { }, } as const; +function suffixNumber(n: number) { + if (n > 3 && n < 21) return 'th'; + switch (n % 10) { + case 1: + return 'st'; + case 2: + return 'nd'; + case 3: + return 'rd'; + default: + return 'th'; + } +} + /** * Format a date with a reusable, pre-configured date format convention. * @param date The date to format. @@ -33,5 +47,8 @@ export default function ( date: Date, convention: keyof typeof DATE_FORMAT_CONVENTIONS = 'standard', ): string { - return Intl.DateTimeFormat('en-US', DATE_FORMAT_CONVENTIONS[convention]).format(date); + return ( + Intl.DateTimeFormat('en-US', DATE_FORMAT_CONVENTIONS[convention]).format(date) + + (convention === 'onlyDay' ? suffixNumber(date.getDate()) : '') + ); } diff --git a/src/routes/app/(app)/projects/+page.svelte b/src/routes/app/(app)/projects/+page.svelte index 2c3e754d4..7d10a60e5 100644 --- a/src/routes/app/(app)/projects/+page.svelte +++ b/src/routes/app/(app)/projects/+page.svelte @@ -62,10 +62,10 @@
- + - {formatDate(cycle.end, 'onlyDay')} + {formatDate(cycle.end, 'onlyDay')}