parent
b378e57b27
commit
1747f91bf1
@ -1,52 +1,47 @@ |
||||
import React, { Component } from 'react' |
||||
import React from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
import { exportAsFile } from '../../../helpers/utils/util' |
||||
import Copy from '../icon/copy-icon.component' |
||||
import { useI18nContext } from '../../../hooks/useI18nContext' |
||||
import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard' |
||||
|
||||
class ExportTextContainer extends Component { |
||||
render () { |
||||
const { text = '' } = this.props |
||||
const { t } = this.context |
||||
function ExportTextContainer ({ text = '' }) { |
||||
const t = useI18nContext() |
||||
const [copied, handleCopy] = useCopyToClipboard() |
||||
|
||||
return ( |
||||
<div className="export-text-container"> |
||||
<div className="export-text-container__text-container"> |
||||
<div className="export-text-container__text notranslate"> |
||||
{text} |
||||
return ( |
||||
<div className="export-text-container"> |
||||
<div className="export-text-container__text-container"> |
||||
<div className="export-text-container__text notranslate">{text}</div> |
||||
</div> |
||||
<div className="export-text-container__buttons-container"> |
||||
<div |
||||
className="export-text-container__button export-text-container__button--copy" |
||||
onClick={() => { |
||||
handleCopy(text) |
||||
}} |
||||
> |
||||
<Copy size={17} color="#3098DC" /> |
||||
<div className="export-text-container__button-text"> |
||||
{copied ? t('copiedExclamation') : t('copyToClipboard')} |
||||
</div> |
||||
</div> |
||||
<div className="export-text-container__buttons-container"> |
||||
<div |
||||
className="export-text-container__button export-text-container__button--copy" |
||||
onClick={() => copyToClipboard(text)} |
||||
> |
||||
<Copy size={17} color="#3098DC" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('copyToClipboard')} |
||||
</div> |
||||
</div> |
||||
<div |
||||
className="export-text-container__button" |
||||
onClick={() => exportAsFile('', text)} |
||||
> |
||||
<img src="images/download.svg" alt="" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('saveAsCsvFile')} |
||||
</div> |
||||
<div |
||||
className="export-text-container__button" |
||||
onClick={() => exportAsFile('', text)} |
||||
> |
||||
<img src="images/download.svg" alt="" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('saveAsCsvFile')} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
ExportTextContainer.propTypes = { |
||||
text: PropTypes.string, |
||||
} |
||||
|
||||
ExportTextContainer.contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
export default ExportTextContainer |
||||
export default React.memo(ExportTextContainer) |
||||
|
@ -0,0 +1,28 @@ |
||||
import { useState, useCallback } from 'react' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
import { useTimeout } from './useTimeout' |
||||
|
||||
/** |
||||
* useCopyToClipboard |
||||
* |
||||
* @param {number} [delay=3000] - delay in ms |
||||
* |
||||
* @return {[boolean, Function]} |
||||
*/ |
||||
const DEFAULT_DELAY = 3000 |
||||
|
||||
export function useCopyToClipboard (delay = DEFAULT_DELAY) { |
||||
const [copied, setCopied] = useState(false) |
||||
const startTimeout = useTimeout(() => setCopied(false), delay, false) |
||||
|
||||
const handleCopy = useCallback( |
||||
(text) => { |
||||
setCopied(true) |
||||
startTimeout() |
||||
copyToClipboard(text) |
||||
}, |
||||
[startTimeout], |
||||
) |
||||
|
||||
return [copied, handleCopy] |
||||
} |
@ -0,0 +1,46 @@ |
||||
import { useState, useEffect, useRef, useCallback } from 'react' |
||||
|
||||
/** |
||||
* useTimeout |
||||
* |
||||
* @param {Function} cb - callback function inside setTimeout |
||||
* @param {number} delay - delay in ms |
||||
* @param {boolean} [immediate] - determines whether the timeout is invoked immediately |
||||
* |
||||
* @return {Function} |
||||
*/ |
||||
export function useTimeout (cb, delay, immediate = true) { |
||||
const saveCb = useRef() |
||||
const [timeoutId, setTimeoutId] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
saveCb.current = cb |
||||
}, [cb]) |
||||
|
||||
useEffect(() => { |
||||
if (timeoutId !== 'start') { |
||||
return |
||||
} |
||||
|
||||
const id = setTimeout(() => { |
||||
saveCb.current() |
||||
}, delay) |
||||
|
||||
setTimeoutId(id) |
||||
|
||||
return () => { |
||||
clearTimeout(timeoutId) |
||||
} |
||||
}, [delay, timeoutId]) |
||||
|
||||
const startTimeout = useCallback(() => { |
||||
clearTimeout(timeoutId) |
||||
setTimeoutId('start') |
||||
}, [timeoutId]) |
||||
|
||||
if (immediate) { |
||||
startTimeout() |
||||
} |
||||
|
||||
return startTimeout |
||||
} |
@ -1,85 +1,102 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import React from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { Redirect } from 'react-router-dom' |
||||
|
||||
import Identicon from '../../../../components/ui/identicon' |
||||
import Copy from '../../../../components/ui/icon/copy-icon.component' |
||||
import Button from '../../../../components/ui/button/button.component' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
|
||||
import Tooltip from '../../../../components/ui/tooltip-v2' |
||||
import { useI18nContext } from '../../../../hooks/useI18nContext' |
||||
import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard' |
||||
|
||||
function quadSplit (address) { |
||||
return '0x ' + address.slice(2).match(/.{1,4}/g).join(' ') |
||||
return ( |
||||
'0x ' + |
||||
address |
||||
.slice(2) |
||||
.match(/.{1,4}/g) |
||||
.join(' ') |
||||
) |
||||
} |
||||
|
||||
export default class ViewContact extends PureComponent { |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
function ViewContact ({ |
||||
history, |
||||
name, |
||||
address, |
||||
checkSummedAddress, |
||||
memo, |
||||
editRoute, |
||||
listRoute, |
||||
}) { |
||||
const t = useI18nContext() |
||||
const [copied, handleCopy] = useCopyToClipboard() |
||||
|
||||
static propTypes = { |
||||
name: PropTypes.string, |
||||
address: PropTypes.string, |
||||
history: PropTypes.object, |
||||
checkSummedAddress: PropTypes.string, |
||||
memo: PropTypes.string, |
||||
editRoute: PropTypes.string, |
||||
listRoute: PropTypes.string.isRequired, |
||||
if (!address) { |
||||
return <Redirect to={{ pathname: listRoute }} /> |
||||
} |
||||
|
||||
render () { |
||||
const { t } = this.context |
||||
const { history, name, address, checkSummedAddress, memo, editRoute, listRoute } = this.props |
||||
|
||||
if (!address) { |
||||
return <Redirect to={{ pathname: listRoute }} /> |
||||
} |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__header address-book__header"> |
||||
<Identicon address={address} diameter={60} /> |
||||
<div className="address-book__header__name">{ name }</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<Button |
||||
type="secondary" |
||||
onClick={() => { |
||||
history.push(`${editRoute}/${address}`) |
||||
}} |
||||
> |
||||
{t('edit')} |
||||
</Button> |
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__header address-book__header"> |
||||
<Identicon address={address} diameter={60} /> |
||||
<div className="address-book__header__name">{name}</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<Button |
||||
type="secondary" |
||||
onClick={() => { |
||||
history.push(`${editRoute}/${address}`) |
||||
}} |
||||
> |
||||
{t('edit')} |
||||
</Button> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label"> |
||||
{t('ethereumPublicAddress')} |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label"> |
||||
{ t('ethereumPublicAddress') } |
||||
<div className="address-book__view-contact__group__value"> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{quadSplit(checkSummedAddress)} |
||||
</div> |
||||
<div className="address-book__view-contact__group__value"> |
||||
<div |
||||
className="address-book__view-contact__group__static-address" |
||||
> |
||||
{ quadSplit(checkSummedAddress) } |
||||
</div> |
||||
<Tooltip |
||||
position="bottom" |
||||
title={copied ? t('copiedExclamation') : t('copyToClipboard')} |
||||
> |
||||
<button |
||||
className="address-book__view-contact__group__static-address--copy-icon" |
||||
onClick={() => copyToClipboard(checkSummedAddress)} |
||||
onClick={() => { |
||||
handleCopy(checkSummedAddress) |
||||
}} |
||||
> |
||||
<Copy size={20} color="#3098DC" /> |
||||
</button> |
||||
</div> |
||||
</Tooltip> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label--capitalized"> |
||||
{ t('memo') } |
||||
</div> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{ memo } |
||||
</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label--capitalized"> |
||||
{t('memo')} |
||||
</div> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{memo} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
ViewContact.propTypes = { |
||||
name: PropTypes.string, |
||||
address: PropTypes.string, |
||||
history: PropTypes.object, |
||||
checkSummedAddress: PropTypes.string, |
||||
memo: PropTypes.string, |
||||
editRoute: PropTypes.string, |
||||
listRoute: PropTypes.string.isRequired, |
||||
} |
||||
|
||||
export default React.memo(ViewContact) |
||||
|
Loading…
Reference in new issue