Skip to content

Commit

Permalink
add recipient flow
Browse files Browse the repository at this point in the history
  • Loading branch information
KorbinianK committed Oct 27, 2023
1 parent 16c455d commit f71c7b7
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 47 deletions.
39 changes: 31 additions & 8 deletions packages/bridge-ui-v2/src/components/Bridge/NFTBridge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,23 @@
import type Amount from './Amount.svelte';
import type IdInput from './IDInput/IDInput.svelte';
import ImportStep from './NFTBridgeSteps/ImportStep.svelte';
import RecipientStep from './NFTBridgeSteps/RecipientStep.svelte';
import ReviewStep from './NFTBridgeSteps/ReviewStep.svelte';
import type { ProcessingFee } from './ProcessingFee';
import type Recipient from './Recipient.svelte';
import {
activeBridge,
bridgeService,
destNetwork as destinationChain,
enteredAmount,
processingFee,
processingFeeMethod,
recipientAddress,
selectedToken,
} from './state';
import { NFTSteps } from './types';
let amountComponent: Amount;
let recipientComponent: Recipient;
let recipientStepComponent: RecipientStep;
let processingFeeComponent: ProcessingFee;
let actionsComponent: Actions;
let importMethod: 'scan' | 'manual' = 'scan';
Expand Down Expand Up @@ -181,7 +182,7 @@
const tokenIds =
nftIdArray.length > 0 ? nftIdArray.map((num) => BigInt(num)) : selectedNFT.map((nft) => BigInt(nft.tokenId));
const bridgeArgs = await getBridgeArgs($selectedToken, $enteredAmount, commonArgs, selectedNFT, nftIdArray);
const bridgeArgs = await getBridgeArgs($selectedToken, $enteredAmount, commonArgs, nftIdArray);
const args = { ...bridgeArgs, tokenIds };
Expand Down Expand Up @@ -242,9 +243,9 @@
const resetForm = () => {
//we check if these are still mounted, as the user might have left the page
if (amountComponent) amountComponent.clearAmount();
if (recipientComponent) recipientComponent.clearRecipient();
if (processingFeeComponent) processingFeeComponent.resetProcessingFee();
if (addressInputComponent) addressInputComponent.clearAddress();
if (recipientStepComponent) recipientStepComponent.reset();
// Update balance after bridging
if (amountComponent) amountComponent.updateBalance();
Expand Down Expand Up @@ -335,6 +336,10 @@
});
};
const handleTransactionDetailsClick = () => {
activeStep = NFTSteps.RECIPIENT;
};
// Whenever the user switches bridge types, we should reset the forms
$: $activeBridge && (resetForm(), (activeStep = NFTSteps.IMPORT));
Expand All @@ -345,6 +350,7 @@
nftStepDescription = $t(`bridge.description.nft.${stepKey}`);
nextStepButtonText = getStepText();
}
onDestroy(() => {
resetForm();
});
Expand All @@ -353,12 +359,15 @@
<div class="f-col">
<Stepper {activeStep}>
<Step stepIndex={NFTSteps.IMPORT} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.IMPORT}
>{$t('bridge.title.nft.import')}</Step>
>{$t('bridge.nft.step.import.title')}</Step>
<Step stepIndex={NFTSteps.REVIEW} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.REVIEW}
>{$t('bridge.title.nft.review')}</Step>
>{$t('bridge.nft.step.review.title')}</Step>
<Step stepIndex={NFTSteps.CONFIRM} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.CONFIRM}
>{$t('bridge.title.nft.confirm')}</Step>
>{$t('bridge.nft.step.confirm.title')}</Step>
</Stepper>

{$processingFeeMethod}

<Card class="mt-[32px] w-full md:w-[524px]" title={nftStepTitle} text={nftStepDescription}>
<div class="space-y-[30px]">
<!-- IMPORT STEP -->
Expand All @@ -373,12 +382,14 @@
bind:validating={validatingImport} />
<!-- REVIEW STEP -->
{:else if activeStep === NFTSteps.REVIEW}
<ReviewStep />
<ReviewStep on:editTransactionDetails={handleTransactionDetailsClick} />
<!-- CONFIRM STEP -->
{:else if activeStep === NFTSteps.CONFIRM}
<div class="f-between-center gap-4">
<ChainSelectorWrapper />
</div>
{:else if activeStep === NFTSteps.RECIPIENT}
<RecipientStep bind:this={recipientStepComponent} />
{/if}
<!--
User Actions
Expand Down Expand Up @@ -421,6 +432,18 @@
</button>
</div>
{/if}
{:else if activeStep === NFTSteps.RECIPIENT}
<div class="f-col w-full">
<Button
disabled={!canProceed}
type="primary"
class="px-[28px] py-[14px] rounded-full flex-1 w-auto text-white"
on:click={() => (activeStep = NFTSteps.REVIEW)}><span class="body-bold">{nextStepButtonText}</span></Button>

<button on:click={previousStep} class="flex justify-center py-3 link">
{$t('common.back')}
</button>
</div>
{/if}
</div>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { ProcessingFee } from '../ProcessingFee';
import Recipient from '../Recipient.svelte';
let recipientComponent: Recipient;
let processingFeeComponent: ProcessingFee;
export let hasEnoughEth: boolean = false;
export const reset = () => {
recipientComponent.clearRecipient();
processingFeeComponent.resetProcessingFee();
};
</script>

<Recipient bind:this={recipientComponent} />
<ProcessingFee bind:this={processingFeeComponent} bind:hasEnoughEth />

<div class="h-sep" />
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import { chainConfig } from '$chainConfig';
Expand All @@ -13,9 +14,12 @@
let recipientComponent: Recipient;
let processingFeeComponent: ProcessingFee;
let hasEnoughEth: boolean;
$: nftsToDisplay = $selectedNFTs ? $selectedNFTs : [];
const dispatch = createEventDispatcher();
enum NFTView {
CARDS,
LIST,
Expand All @@ -29,6 +33,10 @@
nftView = NFTView.CARDS;
}
};
const editTransactionDetails = () => {
dispatch('editTransactionDetails');
};
</script>

<div class="container mx-auto inline-block align-middle space-y-[25px]">
Expand Down Expand Up @@ -111,13 +119,14 @@ NFT List or Card View
<!--
Recipient & Processing Fee
-->

<div class="f-col">
<div class="f-between-center mb-[10px]">
<div class="font-bold text-primary-content">{$t('bridge.nft.step.review.recipient_details')}</div>
<button class="flex justify-start link"> Edit </button>
<button class="flex justify-start link" on:click={editTransactionDetails}> Edit </button>
</div>
<Recipient bind:this={recipientComponent} small />
<ProcessingFee bind:this={processingFeeComponent} small />
<ProcessingFee bind:this={processingFeeComponent} small bind:hasEnoughEth />
</div>

<div class="h-sep" />
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as ImportStep } from './ImportStep.svelte';
export { default as RecipientStep } from './RecipientStep.svelte';
export { default as ReviewStep } from './ReviewStep.svelte';
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@
import { parseToWei } from '$libs/util/parseToWei';
import { uid } from '$libs/util/uid';
import { processingFee } from '../state';
import { processingFee, processingFeeMethod } from '../state';
import NoneOption from './NoneOption.svelte';
import RecommendedFee from './RecommendedFee.svelte';
export let small = false;
export let hasEnoughEth = false;
let dialogId = `dialog-${uid()}`;
let selectedFeeMethod = ProcessingFeeMethod.RECOMMENDED;
let prevOptionSelected = ProcessingFeeMethod.RECOMMENDED;
let recommendedAmount = BigInt(0);
let calculatingRecommendedAmount = false;
let errorCalculatingRecommendedAmount = false;
let hasEnoughEth = false;
let calculatingEnoughEth = false;
let errorCalculatingEnoughEth = false;
Expand All @@ -37,14 +36,14 @@
// Public API
export function resetProcessingFee() {
inputBox?.clear();
selectedFeeMethod = ProcessingFeeMethod.RECOMMENDED;
$processingFeeMethod = ProcessingFeeMethod.RECOMMENDED;
}
function closeModal() {
// Let's check if we are closing with CUSTOM method selected and zero amount entered
if (selectedFeeMethod === ProcessingFeeMethod.CUSTOM && $processingFee === BigInt(0)) {
if ($processingFeeMethod === ProcessingFeeMethod.CUSTOM && $processingFee === BigInt(0)) {
// If so, let's switch to RECOMMENDED method
selectedFeeMethod = ProcessingFeeMethod.RECOMMENDED;
$processingFeeMethod = ProcessingFeeMethod.RECOMMENDED;
}
removeEscKeyListener();
modalOpen = false;
Expand All @@ -53,14 +52,14 @@
function openModal() {
// Keep track of the selected method before opening the modal
// so if we cancel we can go back to the previous method
prevOptionSelected = selectedFeeMethod;
prevOptionSelected = $processingFeeMethod;
addEscKeyListener();
modalOpen = true;
}
function cancelModal() {
inputBox?.clear();
selectedFeeMethod = prevOptionSelected;
$processingFeeMethod = prevOptionSelected;
closeModal();
}
Expand All @@ -69,7 +68,7 @@
}
function inputProcessFee(event: Event) {
if (selectedFeeMethod !== ProcessingFeeMethod.CUSTOM) return;
if ($processingFeeMethod !== ProcessingFeeMethod.CUSTOM) return;
const { value } = event.target as HTMLInputElement;
$processingFee = parseToWei(value);
Expand Down Expand Up @@ -119,20 +118,21 @@
function unselectNoneIfNotEnoughETH(method: ProcessingFeeMethod, enoughEth: boolean) {
if (method === ProcessingFeeMethod.NONE && !enoughEth) {
selectedFeeMethod = ProcessingFeeMethod.RECOMMENDED;
$processingFeeMethod = ProcessingFeeMethod.RECOMMENDED;
// We need to manually trigger this update because we are already in an update
// cicle, meaning the change above will not start a new one. This is how Svelte
// works, batching all the changes and kicking off an update cicle. This could
// also prevent infinite loops. It's safe though to call this function because
// we're not changing state that could potentially end up in such situation.
updateProcessingFee(selectedFeeMethod, recommendedAmount);
updateProcessingFee($processingFeeMethod, recommendedAmount);
}
}
$: updateProcessingFee(selectedFeeMethod, recommendedAmount);
$: unselectNoneIfNotEnoughETH(selectedFeeMethod, hasEnoughEth);
$: {
updateProcessingFee($processingFeeMethod, recommendedAmount);
}
$: unselectNoneIfNotEnoughETH($processingFeeMethod, hasEnoughEth);
</script>

{#if small}
Expand All @@ -145,7 +145,9 @@
{:else if errorCalculatingRecommendedAmount}
{$t('processing_fee.recommended.error')}
{:else}
{formatEther($processingFee ?? BigInt(0))} ETH
{formatEther($processingFee ?? BigInt(0))} ETH {#if $processingFee !== recommendedAmount}
<span class="text-primary-link">| Customized</span>
{/if}
{/if}
</span>
</div>
Expand All @@ -169,7 +171,9 @@
{:else if errorCalculatingRecommendedAmount}
{$t('processing_fee.recommended.error')}
{:else}
{formatEther($processingFee ?? BigInt(0))} ETH
{formatEther($processingFee ?? BigInt(0))} ETH {#if $processingFee !== recommendedAmount}
<span class="text-primary-link">| Customized</span>
{/if}
{/if}
</span>

Expand Down Expand Up @@ -206,7 +210,7 @@
type="radio"
value={ProcessingFeeMethod.RECOMMENDED}
name="processingFeeMethod"
bind:group={selectedFeeMethod} />
bind:group={$processingFeeMethod} />
</li>

<!-- NONE -->
Expand All @@ -227,7 +231,7 @@
disabled={!hasEnoughEth}
value={ProcessingFeeMethod.NONE}
name="processingFeeMethod"
bind:group={selectedFeeMethod} />
bind:group={$processingFeeMethod} />
</div>

{#if !hasEnoughEth}
Expand All @@ -251,16 +255,16 @@
type="radio"
value={ProcessingFeeMethod.CUSTOM}
name="processingFeeMethod"
bind:group={selectedFeeMethod} />
bind:group={$processingFeeMethod} />
</li>
</ul>
<div class="relative f-items-center my-[20px]">
{#if selectedFeeMethod === ProcessingFeeMethod.CUSTOM}
{#if $processingFeeMethod === ProcessingFeeMethod.CUSTOM}
<InputBox
type="number"
min="0"
placeholder="0.01"
disabled={selectedFeeMethod !== ProcessingFeeMethod.CUSTOM}
disabled={$processingFeeMethod !== ProcessingFeeMethod.CUSTOM}
class="w-full input-box p-6 pr-16 title-subsection-bold placeholder:text-tertiary-content"
on:input={inputProcessFee}
bind:this={inputBox} />
Expand Down
13 changes: 5 additions & 8 deletions packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
import type { Address } from 'viem';
Expand All @@ -15,7 +14,7 @@
// Public API
export const clearRecipient = () => {
addressInput.clearAddress(); // update UI
if (addressInput) addressInput.clearAddress(); // update UI
$recipientAddress = null; // update state
};
Expand Down Expand Up @@ -77,10 +76,6 @@
window.removeEventListener('keydown', escKeyListener);
};
onDestroy(() => {
removeEscKeyListener();
});
$: modalOpenChange(modalOpen);
$: ethereumAddressBinding = $recipientAddress || undefined;
Expand All @@ -95,7 +90,7 @@
{#if displayedRecipient}
{shortenAddress(displayedRecipient, 8, 10)}
{#if displayedRecipient !== $account?.address}
<span class="text-primary-content">| Customized</span>
<span class="text-primary-link">| Customized</span>
{/if}
{:else}
{$t('recipient.placeholder')}
Expand All @@ -116,7 +111,9 @@
<span class="body-small-regular text-secondary-content mt-[4px]">
{#if displayedRecipient}
{shortenAddress(displayedRecipient, 15, 13)}
<span class="text-secondary">{displayedRecipient !== $account?.address ? '' : '| Customized'}</span>
{#if displayedRecipient !== $account?.address}
<span class="text-primary-link">| {$t('common.customized')}</span>
{/if}
{:else}
{$t('recipient.placeholder')}
{/if}
Expand Down
Loading

0 comments on commit f71c7b7

Please sign in to comment.