Skip to content

Commit

Permalink
Merge branch 'development' of github.com:multiversx/mx-explorer-dapp …
Browse files Browse the repository at this point in the history
…into battlenet-setup
  • Loading branch information
radumojic committed Aug 26, 2024
2 parents 109deb9 + 060810b commit 8edb5ff
Show file tree
Hide file tree
Showing 42 changed files with 745 additions and 70 deletions.
1 change: 1 addition & 0 deletions src/appConstants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const AUCTION_LIST_MIN_DISPLAY_ROW_COUNT = 6;
export const LEGACY_DELEGATION_NODES_IDENTITY = 'multiversx';
export const HEROTAG_SUFFIX = '.elrond';
export const TEMP_LOCAL_NOTIFICATION_DISMISSED = 'tempNotificationDismissed2';
export const CUSTOM_NETWORK_ID = 'custom-network';
export const NEW_VERSION_NOTIFICATION = 'newExplorerVersion';

export const SC_INIT_CHARACTERS_LENGTH = 13;
Expand Down
6 changes: 6 additions & 0 deletions src/assets/scss/_shared-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
border-bottom-right-radius: $input-border-radius-lg !important;
}
}

&.input-group-search {
width: auto;
.form-control {
Expand All @@ -55,6 +56,11 @@
border-top-right-radius: $input-border-radius-sm !important;
border-bottom-right-radius: $input-border-radius-sm !important;
}
&.has-validation {
.input-group-text {
height: 2.063rem;
}
}
}
&.has-validation {
.input-group-text {
Expand Down
1 change: 1 addition & 0 deletions src/assets/scss/components/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import '../../../components/BlocksTable/blocksTable.styles.scss';
@import '../../../components/Cards/cards.styles.scss';
@import '../../../components/Chart/chart.styles.scss';
@import '../../../components/CustomNetwork/customNetwork.styles.scss';
@import '../../../components/DataDecode/dataDecode.styles.scss';
@import '../../../components/DetailItem/detailItem.styles.scss';
@import '../../../components/ExpandRow/expandRow.styles.scss';
Expand Down
2 changes: 1 addition & 1 deletion src/components/CollapsibleArrows/CollapsibleArrows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const CollapsibleArrows = ({
}: CollapsibleArrowsPropsType) => {
return (
<FontAwesomeIcon
className={classNames('ms-auto', className)}
className={classNames(className)}
size={size}
icon={expanded ? faChevronUp : faChevronDown}
/>
Expand Down
162 changes: 162 additions & 0 deletions src/components/CustomNetwork/CustomNetworkDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import React, { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import { Collapse } from 'react-bootstrap';
import { useSelector } from 'react-redux';

import { CUSTOM_NETWORK_ID } from 'appConstants';
import { CollapsibleArrows, CopyButton } from 'components';
import { networks } from 'config';
import { storage, scrollToElement } from 'helpers';
import { useGetNetworkChangeLink } from 'hooks';
import { faTrash, faCheck } from 'icons/regular';
import { activeNetworkSelector } from 'redux/selectors';
import { WithClassnameType } from 'types';

export interface NetworkDetailUIType {
title: string;
description: React.ReactNode;
}

const NetworkDetail = ({ title, description }: NetworkDetailUIType) => {
return (
<div className='d-flex flex-wrap align-items-center gap-1'>
<div>{title}:</div>
<div className='text-neutral-100 text-strong'>{description}</div>
</div>
);
};

export const CustomNetworkDetails = ({ className }: WithClassnameType) => {
const getNetworkChangeLink = useGetNetworkChangeLink();
const activeNetwork = useSelector(activeNetworkSelector);
const { isCustom: activeNetworkIsCustom } = activeNetwork;

const configCustomNetwork = networks.filter((network) => network.isCustom)[0];
const existingCustomNetwork = activeNetworkIsCustom
? activeNetwork
: configCustomNetwork;

const [open, setOpen] = useState(false);

const isSavedCustomNetworkActive =
configCustomNetwork?.id === activeNetwork?.id;
const defaultNetwork = networks.find((network) => Boolean(network.default));
const defaultNetworkId = defaultNetwork?.id ?? networks[0]?.id;

const removeNetwork = () => {
storage.removeFromLocal(CUSTOM_NETWORK_ID);
window.location.href = getNetworkChangeLink({
networkId: defaultNetworkId
});
};

const applyNetwork = () => {
window.location.href = getNetworkChangeLink({
networkId: CUSTOM_NETWORK_ID
});
};

if (!existingCustomNetwork) {
return null;
}

return (
<div className={classNames('custom-network-details', className)}>
<button
type='button'
onClick={() => {
setOpen(!open);
}}
aria-controls='custom-network-details'
aria-expanded={open}
className='btn-unstyled d-flex align-items-center justify-content-between'
>
Network Details
<CollapsibleArrows expanded={open} className='ms-2' />
</button>
<Collapse
in={open}
onEntered={() => {
scrollToElement('.custom-network-details', 50);
}}
>
<div id='custom-network-details' className='mx-n2'>
<div className='bg-neutral-850 rounded d-flex flex-column gap-2 mt-2 p-2'>
{!isSavedCustomNetworkActive && (
<>
<div>Saved Custom Network Config</div>
<NetworkDetail
title='Active'
description={<code className='text-warning'>false</code>}
/>
</>
)}
{existingCustomNetwork.name && (
<NetworkDetail
title='Name'
description={existingCustomNetwork.name}
/>
)}
{existingCustomNetwork.apiAddress && (
<NetworkDetail
title='API Address'
description={
<div className='bg-neutral-950 rounded p-1'>
<code>{existingCustomNetwork.apiAddress}</code>{' '}
<CopyButton
text={existingCustomNetwork.apiAddress}
className='copy-button'
/>
</div>
}
/>
)}
{existingCustomNetwork.chainId && (
<NetworkDetail
title='Chain Id'
description={
<span className='badge badge-sm'>
{existingCustomNetwork.chainId}
</span>
}
/>
)}
{existingCustomNetwork.egldLabel && (
<NetworkDetail
title='Default Token Label'
description={existingCustomNetwork.egldLabel}
/>
)}
<div className='d-flex gap-3 align-items-center'>
{!isSavedCustomNetworkActive && (
<button
type='button'
onClick={(e) => {
e.preventDefault();
applyNetwork();
}}
className='btn btn-sm btn-primary align-items-center justify-content-center d-flex flex-grow-1'
>
<FontAwesomeIcon icon={faCheck} className='me-2' />
Apply
</button>
)}
<button
type='button'
onClick={(e) => {
e.preventDefault();
removeNetwork();
}}
className='btn btn-sm btn-dark-alt align-items-center justify-content-center d-flex flex-grow-1'
>
<FontAwesomeIcon icon={faTrash} className='me-2' />
Remove
</button>
</div>
</div>
</div>
</Collapse>
</div>
);
};
100 changes: 100 additions & 0 deletions src/components/CustomNetwork/CustomNetworkInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { useEffect, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import { useSelector } from 'react-redux';

import { networks } from 'config';
import { useCustomNetwork } from 'hooks';
import { faCircleNotch } from 'icons/regular';
import { faCheck } from 'icons/solid';
import { activeNetworkSelector } from 'redux/selectors';
import { WithClassnameType } from 'types';

export const CustomNetworkInput = ({ className }: WithClassnameType) => {
const activeNetwork = useSelector(activeNetworkSelector);
const { isCustom: activeNetworkIsCustom } = activeNetwork;

const configCustomNetwork = networks.filter((network) => network.isCustom)[0];
const existingCustomNetwork = activeNetworkIsCustom
? activeNetwork
: configCustomNetwork;

const [customNetworkUrl, setcustomNetworkUrl] = useState<string>(
existingCustomNetwork?.apiAddress ?? ''
);
const [generalError, setGeneralError] = useState('');
const { setCustomNetwork, isSaving, errors } =
useCustomNetwork(customNetworkUrl);

const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.preventDefault();
setCustomNetwork();
}
};

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setGeneralError('');
setcustomNetworkUrl(e.target.value);
};

useEffect(() => {
if (errors?.apiAddress) {
setGeneralError(errors.apiAddress);
}
}, [errors]);

return (
<form
className={classNames(
'custom-network-input input-group-black w-100 d-flex',
className
)}
>
<div className='input-group input-group-sm input-group-seamless has-validation'>
<input
type='text'
className='form-control text-truncate'
placeholder='API Address'
name='requestType'
data-testid='customNetwork'
required
value={customNetworkUrl}
onChange={handleChange}
onKeyDown={handleKeyDown}
disabled={isSaving}
aria-label='API Address'
aria-describedby='customNetwork-addon'
/>
<button
type='submit'
className='input-group-text'
onClick={(e) => {
e.preventDefault();
setCustomNetwork();
}}
data-testid='customNetworkButton'
aria-label='customNetwork'
>
{isSaving ? (
<FontAwesomeIcon
icon={faCircleNotch}
spin
className='me-1 text-primary'
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className={classNames('me-1', {
'text-primary': activeNetworkIsCustom
})}
/>
)}
</button>
{generalError && (
<div className='invalid-feedback d-block'>{generalError}</div>
)}
</div>
</form>
);
};
25 changes: 25 additions & 0 deletions src/components/CustomNetwork/CustomNetworkMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { forwardRef } from 'react';
import classNames from 'classnames';
import { Dropdown } from 'react-bootstrap';

import { CustomNetworkInput, CustomNetworkDetails } from 'components';

export const CustomNetworkMenu = forwardRef(
({ children, className, style }: any, ref: any) => {
return (
<div
ref={ref}
className={classNames('custom-network-menu', className)}
style={style}
>
{children}
<Dropdown.Divider />
<div className='d-flex flex-column gap-2 px-3 pb-2'>
Custom Network API Address
<CustomNetworkInput />
<CustomNetworkDetails />
</div>
</div>
);
}
);
9 changes: 9 additions & 0 deletions src/components/CustomNetwork/customNetwork.styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.custom-network-menu {
width: 15rem;
--dropdown-divider-bg: var(--neutral-700);
.input-group-seamless {
.form-control {
padding-right: 2.5rem;
}
}
}
3 changes: 3 additions & 0 deletions src/components/CustomNetwork/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './CustomNetworkDetails';
export * from './CustomNetworkInput';
export * from './CustomNetworkMenu';
22 changes: 12 additions & 10 deletions src/components/SharedIdentity/IdentityCard/IdentityCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,18 @@ export const IdentityCard = ({ identity }: { identity: IdentityType }) => {
className='detail-card'
/>

<div className='d-flex flex-fill align-items-end justify-content-end stake-card'>
<a
className='btn btn-block btn-sm btn-primary'
target='_blank'
rel='noreferrer nofollow noopener'
href={walletAddress}
>
Stake now
</a>
</div>
{walletAddress && (
<div className='d-flex flex-fill align-items-end justify-content-end stake-card'>
<a
className='btn btn-block btn-sm btn-primary'
target='_blank'
rel='noreferrer nofollow noopener'
href={walletAddress}
>
Stake now
</a>
</div>
)}
</div>

<div className='d-flex flex-row flex-wrap gap-3 mt-3'>
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './Cards';
export * from './CollapsibleArrows';
export * from './CollectionBlock';
export * from './CopyButton';
export * from './CustomNetwork';
export * from './DataDecode';
export * from './DetailItem';
export * from './ExpandRow';
Expand Down
Loading

0 comments on commit 8edb5ff

Please sign in to comment.