Skip to content

Commit

Permalink
update design and some refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
KorbinianK committed Oct 24, 2023
1 parent 1fec243 commit ad16ed8
Show file tree
Hide file tree
Showing 26 changed files with 798 additions and 320 deletions.
2 changes: 1 addition & 1 deletion packages/bridge-ui-v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ These are are the additional configuration files that have to be filled in:
| **/config/configuredBridges.json** | Defines the chains that are connected via taiko bridges and lists the contract addresses |
| **/config/configuredChains.json** | Defines some metadata for the chains, such as name, icons, explorer URL, etc. |
| **/config/configuredRelayer.json** | If chains have a relayer, the URL and the chain IDs it covers are entered here |
| **/config/configuredCustomTokens.json** | Defines a list of tokens that should be available in the token dropdowns |
| **/config/configuredCustomTokens.json** | Defines a list of tokens that should be availabe in the token dropdowns |

---

Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-ui-v2/__mocks__/parseNFTMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { vi } from 'vitest';

export const parseNFTMetadata = vi.fn();
export const fetchNFTMetadata = vi.fn();
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
export let labelText = $t('inputs.address_input.label.default');
export let isDisabled = false;
export let quiet = false;
export let state: State = State.Default;
export let state: State = State.DEFAULT;
export const validateAddress = () => {
validateEthereumAddress(ethereumAddress);
};
export const clearAddress = () => {
state = State.Default;
state = State.DEFAULT;
if (input) input.value = '';
validateEthereumAddress('');
};
Expand All @@ -43,21 +43,21 @@
addr = address as string;
}
if (addr.length >= 2 && !addr.startsWith('0x')) {
state = State.Invalid;
state = State.INVALID;
return;
}
if (addr.length < 42) {
state = State.TooShort;
state = State.TOO_SHORT;
} else {
if (isAddress(addr)) {
state = State.Valid;
state = State.VALID;
} else {
state = State.Invalid;
state = State.INVALID;
}
dispatch('input', addr);
}
dispatch('addressvalidation', { isValidEthereumAddress: state === State.Valid, addr });
dispatch('addressvalidation', { isValidEthereumAddress: state === State.VALID, addr });
};
onMount(() => {
Expand All @@ -80,7 +80,7 @@
bind:value={ethereumAddress}
on:input={(e) => validateEthereumAddress(e.target)}
class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content {$$props.class}
{state === State.Valid ? 'success' : ethereumAddress && state !== State.Validating ? 'error' : ''}
{state === State.VALID ? 'success' : ethereumAddress && state !== State.VALIDATING ? 'error' : ''}
" />
<button class="absolute right-6 uppercase body-bold text-secondary-content" on:click={clearAddress}>
<Icon type="x-close-circle" fillClass="fill-primary-icon" size={24} />
Expand All @@ -90,11 +90,11 @@

{#if !quiet}
<div class="min-h-[20px] !mt-3">
{#if state === State.Invalid && ethereumAddress}
{#if state === State.INVALID && ethereumAddress}
<FlatAlert type="error" forceColumnFlow message={$t('inputs.address_input.errors.invalid')} />
{:else if state === State.TooShort && ethereumAddress}
{:else if state === State.TOO_SHORT && ethereumAddress}
<FlatAlert type="warning" forceColumnFlow message={$t('inputs.address_input.errors.too_short')} />
{:else if state === State.Valid}
{:else if state === State.VALID}
<FlatAlert type="success" forceColumnFlow message={$t('inputs.address_input.success')} />
{/if}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export enum AddressInputState {
Default,
Valid,
Invalid,
TooShort,
Validating,
DEFAULT,
VALID,
INVALID,
TOO_SHORT,
VALIDATING,
}
3 changes: 1 addition & 2 deletions packages/bridge-ui-v2/src/components/Bridge/Amount.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@
{/if}
</div>
</div>

<div class="relative">
<div class="relative f-items-center">
<InputBox
Expand All @@ -260,7 +259,7 @@
error={$insufficientBalance}
on:input={inputAmount}
bind:this={inputBox}
class="py-6 pr-16 px-[26px] title-subsection-bold border-0" />
class="py-6 pr-16 px-[26px] title-subsection-bold border-0 {$$props.class}" />
<!-- TODO: talk to Jane about the MAX button and its styling -->
<button
class="absolute right-6 uppercase hover:font-bold"
Expand Down
40 changes: 20 additions & 20 deletions packages/bridge-ui-v2/src/components/Bridge/IDInput/IDInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,41 @@
import { IDInputState as State } from './state';
export let numbersArray: number[] = [];
export let validIdNumbers: number[] = [];
export let isDisabled = false;
export let enteredIds: string = '';
export let limit = 1;
export let state: State = State.DEFAULT;
export const clearIds = () => {
enteredIds = '';
numbersArray = [];
dispatch('input', { enteredIds, numbersArray });
validIdNumbers = [];
dispatch('inputValidation');
};
const dispatch = createEventDispatcher();
let inputId = `input-${uid()}`;
function validateInput(e: Event) {
const target = e.target as HTMLInputElement;
let newValue = target.value.replace(/\s+/g, '');
const inputArray = newValue.split(',');
if (inputArray.length > limit) {
newValue = inputArray.slice(0, limit).join(',');
function validateInput(idInput: EventTarget | string | null = null) {
state = State.VALIDATING;
if (!idInput) return;
let ids;
if (idInput && idInput instanceof EventTarget) {
ids = (idInput as HTMLInputElement).value.replace(/\s+/g, '');
} else {
ids = idInput as string;
}
enteredIds = newValue;
dispatch('input', { enteredIds, numbersArray });
}
$: {
if (enteredIds === '' || enteredIds.endsWith(',')) {
numbersArray = [];
} else {
const inputArray = enteredIds.split(',');
const isValid = inputArray.every((item) => /^[0-9]+$/.test(item));
numbersArray = isValid ? inputArray.map((num) => parseInt(num)).filter(Boolean) : [];
const inputArray = ids.split(',');
if (inputArray.length > limit) {
ids = inputArray.slice(0, limit).join(',');
}
enteredIds = ids;
const isValid = inputArray.every((item) => /^[0-9]+$/.test(item));
validIdNumbers = isValid ? inputArray.map((num) => parseInt(num)).filter(Boolean) : [];
state = State.VALID;
dispatch('inputValidation');
}
</script>

Expand All @@ -56,7 +56,7 @@
type="text"
placeholder={$t('inputs.token_id_input.placeholder')}
bind:value={enteredIds}
on:input={validateInput}
on:input={(e) => validateInput(e.target)}
class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content {$$props.class}
{state === State.VALID ? 'success' : state === State.DEFAULT ? '' : 'error'}" />
<!-- /*state === State.Valid ? 'success' : state === State.Invalid ? 'error' : '' -->
Expand Down
68 changes: 39 additions & 29 deletions packages/bridge-ui-v2/src/components/Bridge/NFTBridge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { Hash } from '@wagmi/core';
import { onDestroy, tick } from 'svelte';
import { t } from 'svelte-i18n';
import { type Address, getAddress } from 'viem';
import { type Address, getAddress, isAddress } from 'viem';
import { routingContractsMap } from '$bridgeConfig';
import { chainConfig } from '$chainConfig';
Expand All @@ -18,11 +18,11 @@
import { hasBridge } from '$libs/bridge/bridges';
import type { ERC721Bridge } from '$libs/bridge/ERC721Bridge';
import type { ERC1155Bridge } from '$libs/bridge/ERC1155Bridge';
import { fetchNFTs } from '$libs/bridge/fetchNFTs';
import { getBridgeArgs } from '$libs/bridge/getBridgeArgs';
import { handleBridgeError } from '$libs/bridge/handleBridgeErrors';
import { bridgeTxService } from '$libs/storage';
import { ETHToken, type NFT, TokenType } from '$libs/token';
import { fetchNFTImageUrl } from '$libs/token/fetchNFTImageUrl';
import { getCrossChainAddress } from '$libs/token/getCrossChainAddress';
import { getTokenWithInfoFromAddress } from '$libs/token/getTokenWithInfoFromAddress';
import { getConnectedWallet } from '$libs/util/getConnectedWallet';
Expand Down Expand Up @@ -55,6 +55,7 @@
let actionsComponent: Actions;
let importMethod: 'scan' | 'manual' = 'scan';
let nftIdArray: number[] = [];
let contractAddress: Address | string = '';
function onNetworkChange(newNetwork: Network, oldNetwork: Network) {
updateForm();
Expand Down Expand Up @@ -250,7 +251,6 @@
if (nftIdInputComponent) nftIdInputComponent.clearIds();
$selectedToken = ETHToken;
contractAddress = '';
importMethod === 'scan';
scanned = false;
canProceed = false;
Expand All @@ -269,29 +269,16 @@
let nftStepDescription: string;
let nextStepButtonText: string;
let contractAddress: Address | '';
let addressInputComponent: AddressInput;
let nftIdInputComponent: IdInput;
let scanning: boolean = false;
let validatingImport: boolean = false;
let scanned: boolean = false;
let selectedNFT: NFT[];
let canProceed: boolean;
let canProceed: boolean = false;
let foundNFTs: NFT[] = [];
const scanForNFTs = async () => {
scanning = true;
const accountAddress = $account?.address;
const srcChainId = $network?.id;
if (!accountAddress || !srcChainId) return;
const nftsFromAPIs = await fetchNFTs(accountAddress, BigInt(srcChainId));
foundNFTs = nftsFromAPIs.nfts;
scanning = false;
scanned = true;
};
const getStepText = () => {
if (activeStep === NFTSteps.REVIEW) {
return $t('common.confirm');
Expand All @@ -308,22 +295,42 @@
resetForm();
};
const prefetchImage = async () => {
await Promise.all(
nftIdArray.map(async (id) => {
const token = $selectedToken as NFT;
if (token) {
token.tokenId = id;
fetchNFTImageUrl(token).then((nftWithUrl) => {
$selectedToken = nftWithUrl;
selectedNFT = [nftWithUrl];
});
} else {
throw new Error('no token');
}
}),
);
};
const manualImportAction = () => {
if (!$network?.id) throw new Error('network not found');
const srcChainId = $network?.id;
const tokenId = nftIdArray[0];
if (contractAddress && srcChainId)
getTokenWithInfoFromAddress({ contractAddress, srcChainId, owner: $account?.address, tokenId })
.then((token) => {
if (isAddress(contractAddress) && srcChainId)
getTokenWithInfoFromAddress({ contractAddress, srcChainId: srcChainId, tokenId, owner: $account?.address })
.then(async (token) => {
if (!token) throw new Error('no token with info');
selectedNFT = [token as NFT];
// detectedTokenType = token.type;
// idInputState = IDInputState.VALID;
$selectedToken = token;
await prefetchImage();
})
.catch((err) => {
console.error(err);
// detectedTokenType = null;
// addressInputState = AddressInputState.Invalid;
// detectedTokenType = null;
// idInputState = IDInputState.INVALID;
// invalidToken = true;
});
nextStep();
};
Expand Down Expand Up @@ -352,7 +359,6 @@
<Step stepIndex={NFTSteps.CONFIRM} currentStepIndex={activeStep} isActive={activeStep === NFTSteps.CONFIRM}
>{$t('bridge.title.nft.confirm')}</Step>
</Stepper>

<Card class="mt-[32px] w-full md:w-[524px]" title={nftStepTitle} text={nftStepDescription}>
<div class="space-y-[30px]">
<!-- IMPORT STEP -->
Expand All @@ -361,12 +367,11 @@
bind:importMethod
bind:canProceed
bind:selectedNFT
{scanForNFTs}
{nftIdArray}
{contractAddress}
bind:nftIdArray
bind:contractAddress
{foundNFTs}
bind:scanned
bind:scanning />
bind:validating={validatingImport} />
<!-- REVIEW STEP -->
{:else if activeStep === NFTSteps.REVIEW}
<ReviewStep bind:selectedNFT />
Expand All @@ -393,9 +398,12 @@
</div>
{:else if activeStep === NFTSteps.IMPORT}
{#if importMethod === 'manual'}
<div class="h-sep" />

<div class="f-col w-full">
<Button
disabled={!canProceed}
loading={validatingImport}
type="primary"
class="px-[28px] py-[14px] rounded-full flex-1 w-auto text-white"
on:click={manualImportAction}><span class="body-bold">{nextStepButtonText}</span></Button>
Expand All @@ -406,6 +414,8 @@
</div>
{:else if scanned}
<div class="f-col w-full">
<div class="h-sep" />

<Button
disabled={!canProceed}
type="primary"
Expand Down
Loading

0 comments on commit ad16ed8

Please sign in to comment.