@chakra-ui/react#useClipboard JavaScript Examples
The following examples show how to use
@chakra-ui/react#useClipboard.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: components.js From idena-web with MIT License | 6 votes |
export function GetInvitationCopyButton({value, ...props}) {
const {hasCopied, onCopy} = useClipboard(value)
const {t} = useTranslation()
return (
<Flex alignSelf={['center', 'flex-start']} pt={[5, 0]} {...props}>
{hasCopied ? (
<Text
fontSize={['mobile', 'md']}
lineHeight={['18px', null]}
color="green.500"
fontWeight={500}
>
{t('Copied!')}
</Text>
) : (
<FlatButton fontWeight={500} onClick={onCopy}>
{t('Copy')}
</FlatButton>
)}
</Flex>
)
}
Example #2
Source File: SocialLink.jsx From scaffold-directory with MIT License | 6 votes |
SocialLink = ({ id, value }) => {
const Icon = socials[id].icon;
const { hasCopied, onCopy } = useClipboard(value);
const link = socials[id].getLink(value);
return (
<>
{link ? (
<Link href={socials[id].getLink(value)} isExternal>
<Icon w={4} />
</Link>
) : (
<Tooltip label="Copied to your clipboard!" isOpen={hasCopied}>
<Box cursor="pointer" onClick={onCopy}>
<Icon w={4} label={value} />
</Box>
</Tooltip>
)}
</>
);
}
Example #3
Source File: components.js From idena-web with MIT License | 5 votes |
export function ReceiveDrawer({isOpen, onClose, address}) {
const {t} = useTranslation()
const {onCopy, hasCopied} = useClipboard(address)
const size = useBreakpointValue(['lg', 'md'])
const qrSize = useBreakpointValue(['170px', '128px'])
const variant = useBreakpointValue(['outlineMobile', 'outline'])
return (
<Drawer isOpen={isOpen} onClose={onClose}>
<DrawerHeader mb={[12, 8]}>
<Flex direction="column" textAlign={['center', 'start']}>
<Flex
order={[2, 1]}
align="center"
justify="center"
mt={[8, 0]}
h={12}
w={12}
rounded="xl"
bg="blue.012"
>
<ReceiveIcon boxSize={6} color="blue.500" />
</Flex>
<Heading
order={[1, 2]}
color="brandGray.500"
fontSize={['base', 'lg']}
fontWeight={[['bold', 500]]}
lineHeight="base"
mt={[0, 4]}
>
{t(`Receive iDNA`)}
</Heading>
</Flex>
</DrawerHeader>
<DrawerBody>
<Stack spacing={[12, 5]}>
<QRCode
value={address}
style={{height: qrSize, width: qrSize, margin: '0 auto'}}
/>
<FormControl>
<Flex justify="space-between">
<FormLabel fontSize={['base', 'md']}>{t('Address')}</FormLabel>
{hasCopied ? (
<FormLabel fontSize={['base', 'md']}>{t('Copied!')}</FormLabel>
) : (
<FlatButton onClick={onCopy} mb={2.5}>
{t('Copy')}
</FlatButton>
)}
</Flex>
<Input value={address} size={size} variant={variant} isDisabled />
</FormControl>
</Stack>
</DrawerBody>
</Drawer>
)
}
Example #4
Source File: FlutterCodeModalButton.js From blobs.app with MIT License | 5 votes |
FlutterCodeModalButton = ({ edges, growth, seed }) => {
const ID = `${edges}-${growth}-${seed}`;
const code = `///import blobs library
import 'package:blobs/blobs.dart';
///add blob widget
Container(
child: Blob.fromID(
id: ['${ID}'],
size: 400,
),
),
`;
const { hasCopied, onCopy } = useClipboard(ID);
const Actions = () => (
<>
<Button
onClick={onCopy}
variant="heavy"
leftIcon={<CopyIcon fontSize="lg" />}
>
{hasCopied ? 'Copied' : 'Copy ID'}
</Button>
</>
);
return (
<Modal
title="Use it in Flutter"
src={
<Tooltip
label="Copy Flutter code"
aria-label="Copy Flutter code"
hasArrow
variant="default"
>
<IconButton variant="ghost">
<FlutterIcon w={6} h={6} color="gray.400" />
</IconButton>
</Tooltip>
}
actions={<Actions />}
>
<Highlight code={code} lang="dart" />
<Text fontSize="sm">
For more info about the package and documentation, please check the{' '}
<Link href="https://pub.dev/packages/blobs/" isExternal color="primary">
blobs
</Link>{' '}
repository.
</Text>
</Modal>
);
}
Example #5
Source File: HtmlCodeModalButton.js From blobs.app with MIT License | 5 votes |
HtmlCodeModalButton = ({ seed, edges, growth }) => {
const ID = `${edges}-${growth}-${seed}`;
const [code, setCode] = useState(null);
const { hasCopied, onCopy } = useClipboard(code);
const Actions = () => (
<>
<DownloadSVG content={code} filename={`blob_${ID}.svg`} />
<Button
onClick={onCopy}
leftIcon={<CopyIcon fontSize="18px" />}
variant="heavy"
>
{hasCopied ? 'Copied' : 'Copy code'}
</Button>
</>
);
const Content = () => {
const svgEl = document.getElementById('blobSvg');
const markup = svgEl ? formatCode(svgEl.outerHTML) : '';
setCode(markup.replace(/^\s+|\s+$/g, ''));
return <Highlight code={markup} lang="markup" />;
};
return (
<Modal
title="Get the code"
src={
<Tooltip
label="View SVG code"
aria-label="View SVG code"
hasArrow
variant="default"
>
<IconButton variant="ghost">
<HtmlIcon w={6} h={6} color="gray.400" />
</IconButton>
</Tooltip>
}
actions={<Actions />}
>
{() => <Content />}
</Modal>
);
}
Example #6
Source File: index.js From idena-web with MIT License | 4 votes |
export default function HomePage() {
const queryClient = useQueryClient()
const {
t,
i18n: {language},
} = useTranslation()
const [identity] = useIdentity()
const {
address,
state,
online,
delegatee,
delegationEpoch,
pendingUndelegation,
canMine,
canInvite,
canTerminate,
canActivateInvite,
} = identity
const router = useRouter()
const epoch = useEpoch()
const {privateKey} = useAuthState()
const userStatAddress = useBreakpointValue([
address ? `${address.substr(0, 3)}...${address.substr(-4, 4)}` : '',
address,
])
const [showValidationResults, setShowValidationResults] = React.useState()
const {onCopy} = useClipboard(address)
const successToast = useSuccessToast()
const {
isOpen: isOpenKillForm,
onOpen: onOpenKillForm,
onClose: onCloseKillForm,
} = useDisclosure()
const {
data: {balance, stake, replenishedStake},
} = useQuery(['get-balance', address], () => fetchBalance(address), {
initialData: {balance: 0, stake: 0, replenishedStake: 0},
enabled: !!address,
refetchInterval: 30 * 1000,
})
const [validationResultSeen, setValidationResultSeen] = useValidationResults()
useEffect(() => {
if (epoch) {
const {epoch: epochNumber} = epoch
if (epochNumber) {
queryClient.invalidateQueries('get-balance')
setShowValidationResults(!validationResultSeen)
}
}
}, [epoch, queryClient, validationResultSeen])
const [dnaUrl] = React.useState(() =>
typeof window !== 'undefined'
? JSON.parse(sessionStorage.getItem('dnaUrl'))
: null
)
React.useEffect(() => {
if (dnaUrl) {
if (isValidDnaUrl(dnaUrl.route))
router.push({pathname: dnaUrl.route, query: dnaUrl.query})
sessionStorage.removeItem('dnaUrl')
}
}, [dnaUrl, router])
const toDna = toLocaleDna(language, {maximumFractionDigits: 4})
const [
currentOnboarding,
{dismissCurrentTask, next: nextOnboardingTask},
] = useOnboarding()
const eitherOnboardingState = (...states) =>
eitherState(currentOnboarding, ...states)
const {
isOpen: isOpenActivateInvitePopover,
onOpen: onOpenActivateInvitePopover,
onClose: onCloseActivateInvitePopover,
} = useDisclosure()
const activateInviteDisclosure = useDisclosure()
const activateInviteRef = React.useRef()
const {scrollTo: scrollToActivateInvite} = useScroll(activateInviteRef)
React.useEffect(() => {
if (
isOpenActivateInvitePopover ||
eitherState(
currentOnboarding,
onboardingShowingStep(OnboardingStep.StartTraining),
onboardingShowingStep(OnboardingStep.ActivateInvite)
)
) {
scrollToActivateInvite()
onOpenActivateInvitePopover()
} else onCloseActivateInvitePopover()
}, [
currentOnboarding,
isOpenActivateInvitePopover,
onCloseActivateInvitePopover,
onOpenActivateInvitePopover,
scrollToActivateInvite,
])
const canSubmitFlip = [
IdentityStatus.Verified,
IdentityStatus.Human,
IdentityStatus.Newbie,
].includes(state)
const [{idenaBotConnected}, {persistIdenaBot, skipIdenaBot}] = useAppContext()
const shouldStartIdenaJourney = currentOnboarding.matches(
OnboardingStep.StartTraining
)
const onboardingPopoverPlacement = useBreakpointValue(['top', 'bottom'])
const replenishStakeDisclosure = useDisclosure()
const {
onOpen: onOpenReplenishStakeDisclosure,
onClose: onCloseReplenishStakeDisclosure,
} = replenishStakeDisclosure
React.useEffect(() => {
if (Object.keys(router.query).find(q => q === 'replenishStake')) {
onOpenReplenishStakeDisclosure()
router.push('/home')
}
}, [onOpenReplenishStakeDisclosure, router])
const failToast = useFailToast()
const toast = useSuccessToast()
const stakingApy = useStakingApy()
const ads = useRotatingAds()
const isDesktop = useIsDesktop()
const spoilInviteDisclosure = useDisclosure()
return (
<Layout canRedirect={!dnaUrl} didConnectIdenaBot={idenaBotConnected}>
{!idenaBotConnected && (
<MyIdenaBotAlert onConnect={persistIdenaBot} onSkip={skipIdenaBot} />
)}
<Page pt="10" position="relative">
<MobileApiStatus top={idenaBotConnected ? 4 : 5 / 2} left={4} />
<Stack
w={['100%', '480px']}
direction={['column', 'row']}
spacing={['6', 10]}
>
<Box>
<Stack
spacing={[1, 8]}
w={['100%', '480px']}
align={['center', 'initial']}
ref={activateInviteRef}
>
<UserProfileCard
identity={identity}
my={[4, 0]}
></UserProfileCard>
{canActivateInvite && (
<Box w={['100%', 'initial']} pb={[8, 0]}>
<OnboardingPopover
isOpen={isOpenActivateInvitePopover}
placement={onboardingPopoverPlacement}
>
<PopoverTrigger>
{shouldStartIdenaJourney ? (
<StartIdenaJourneyPanel
onHasActivationCode={activateInviteDisclosure.onOpen}
/>
) : state === IdentityStatus.Invite ? (
<AcceptInvitationPanel />
) : (
<ActivateInvitationPanel />
)}
</PopoverTrigger>
{shouldStartIdenaJourney ? (
<StartIdenaJourneyOnboardingContent
onDismiss={() => {
dismissCurrentTask()
onCloseActivateInvitePopover()
}}
/>
) : state === IdentityStatus.Invite ? (
<AcceptInviteOnboardingContent
onDismiss={() => {
dismissCurrentTask()
onCloseActivateInvitePopover()
}}
/>
) : (
<ActivateInviteOnboardingContent
onDismiss={() => {
dismissCurrentTask()
onCloseActivateInvitePopover()
}}
/>
)}
</OnboardingPopover>
</Box>
)}
{showValidationResults && (
<ValidationReportSummary
onClose={() => setValidationResultSeen()}
/>
)}
<UserStatList title={t('My Wallet')}>
<UserStatistics label={t('Address')} value={userStatAddress}>
<ExternalLink
display={['none', 'initial']}
href={`https://scan.idena.io/address/${address}`}
>
{t('Open in blockchain explorer')}
</ExternalLink>
<CopyIcon
display={['inline', 'none']}
mt="3px"
ml="4px"
boxSize={4}
fill="#96999e"
onClick={() => {
onCopy()
successToast({
title: 'Address copied!',
duration: '5000',
})
}}
/>
</UserStatistics>
<UserStatistics label={t('Balance')} value={toDna(balance)}>
<TextLink display={['none', 'initial']} href="/wallets">
<Stack isInline spacing={0} align="center" fontWeight={500}>
<Text as="span">{t('Send')}</Text>
<ChevronRightIcon boxSize={4} />
</Stack>
</TextLink>
</UserStatistics>
<Button
display={['initial', 'none']}
onClick={() => {
router.push('/wallets')
}}
w="100%"
h={10}
fontSize="15px"
variant="outline"
color="blue.500"
border="none"
borderColor="transparent"
>
{t('Send iDNA')}
</Button>
</UserStatList>
<Stack spacing="2" w="full">
{Boolean(state) && state !== IdentityStatus.Undefined && (
<UserStatList title={t('Stake')}>
<Stack direction={['column', 'row']} spacing={['5', 0]}>
<Stack spacing={['5', '3']} flex={1}>
<Stack spacing="5px">
<UserStat>
<Flex
direction={['row', 'column']}
justify={['space-between', 'flex-start']}
>
<UserStatLabel
color={[null, 'muted']}
fontSize={['mdx', 'md']}
fontWeight={[400, 500]}
lineHeight="4"
>
{t('Balance')}
</UserStatLabel>
<UserStatValue
fontSize={['mdx', 'md']}
lineHeight="4"
mt={[null, '3px']}
>
{toDna(
state === IdentityStatus.Newbie
? (stake - (replenishedStake ?? 0)) * 0.25
: stake
)}
</UserStatValue>
</Flex>
</UserStat>
<Button
display={['none', 'inline-flex']}
variant="link"
color="blue.500"
fontWeight={500}
lineHeight="4"
w="fit-content"
_hover={{
background: 'transparent',
textDecoration: 'underline',
}}
_focus={{
outline: 'none',
}}
onClick={replenishStakeDisclosure.onOpen}
>
{t('Add stake')}
<ChevronRightIcon boxSize="4" />
</Button>
</Stack>
{stake > 0 && state === IdentityStatus.Newbie && (
<AnnotatedUserStatistics
annotation={t(
'You need to get Verified status to get the locked funds into the normal wallet'
)}
label={t('Locked')}
value={toDna(
(stake - (replenishedStake ?? 0)) * 0.75
)}
/>
)}
</Stack>
<Stack spacing="5px" flex={1}>
<UserStat flex={0}>
<Flex
direction={['row', 'column']}
justify={['space-between', 'flex-start']}
>
<UserStatLabel
color={[null, 'muted']}
fontSize={['mdx', 'md']}
fontWeight={[400, 500]}
lineHeight="4"
>
{t('APY')}
</UserStatLabel>
<UserStatValue
fontSize={['mdx', 'md']}
lineHeight="4"
mt={[null, '3px']}
>
{stakingApy > 0 ? toPercent(stakingApy) : '--'}
</UserStatValue>
</Flex>
</UserStat>
<ExternalLink
href={`https://idena.io/staking?amount=${Math.floor(
state === IdentityStatus.Newbie
? (stake - (replenishedStake ?? 0)) * 0.25
: stake
)}`}
display={['none', 'inline-flex']}
>
{t('Staking calculator')}
</ExternalLink>
</Stack>
</Stack>
<Stack display={['inline-flex', 'none']}>
<Button
onClick={replenishStakeDisclosure.onOpen}
w="100%"
h={10}
fontSize="15px"
variant="outline"
color="blue.500"
border="none"
borderColor="transparent"
>
{t('Add stake')}
</Button>
<Button
onClick={() => {
openExternalUrl(
`https://idena.io/staking?amount=${Math.floor(
state === IdentityStatus.Newbie
? (stake - (replenishedStake ?? 0)) * 0.25
: stake
)}`
)
}}
w="100%"
h={10}
fontSize="15px"
variant="outline"
color="blue.500"
border="none"
borderColor="transparent"
>
{t('Staking calculator')}
</Button>
</Stack>
</UserStatList>
)}
<StakingAlert />
</Stack>
</Stack>
{ads?.length > 0 && !isDesktop && (
<Box display={['block', 'none']} mt="6">
<AdCarousel ads={ads} />
</Box>
)}
</Box>
<Stack spacing={[0, 10]} flexShrink={0} w={['100%', 200]}>
{address && privateKey && canMine && (
<Box minH={62} mt={[1, 6]}>
<OnboardingPopover
isOpen={eitherOnboardingState(
onboardingShowingStep(OnboardingStep.ActivateMining)
)}
>
<PopoverTrigger>
<Box
bg="white"
position={
eitherOnboardingState(
onboardingShowingStep(OnboardingStep.ActivateMining)
)
? 'relative'
: 'initial'
}
borderRadius={['mdx', 'md']}
p={[0, 2]}
m={[0, -2]}
zIndex={2}
>
<ActivateMiningForm
privateKey={privateKey}
isOnline={online}
delegatee={delegatee}
delegationEpoch={delegationEpoch}
pendingUndelegation={pendingUndelegation}
onShow={nextOnboardingTask}
/>
</Box>
</PopoverTrigger>
<OnboardingPopoverContent
title={t('Activate mining status')}
onDismiss={nextOnboardingTask}
>
<Text>
{t(
`To become a validator of Idena blockchain you can activate your mining status. Keep your node online to mine iDNA coins.`
)}
</Text>
</OnboardingPopoverContent>
</OnboardingPopover>
</Box>
)}
<Stack spacing={[0, 1]} align="flex-start">
<WideLink
display={['initial', 'none']}
label="Open in blockchain explorer"
href={`https://scan.idena.io/address/${address}`}
isNewTab
>
<Box
boxSize={8}
backgroundColor="brandBlue.10"
borderRadius="10px"
>
<OpenExplorerIcon boxSize={5} mt="6px" ml="6px" />
</Box>
</WideLink>
<WideLink
mt={[0, '2px']}
label={t('Training validation')}
onClick={() => router.push('/try')}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<TestValidationIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('New voting')}
onClick={() => router.push('/oracles/new')}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<OracleIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('New ad')}
onClick={() => router.push('/adn/new')}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<AdsIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('New flip')}
isDisabled={!canSubmitFlip}
onClick={() => router.push('/flips/new')}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<PhotoIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('Invite')}
onClick={() => router.push('/contacts?new')}
isDisabled={!canInvite}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<AddUserIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('Spoil invite')}
onClick={spoilInviteDisclosure.onOpen}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<PooIcon
color="blue.500"
boxSize="5"
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
<WideLink
label={t('Terminate')}
onClick={onOpenKillForm}
isDisabled={!canTerminate}
>
<Box
boxSize={[8, 5]}
backgroundColor={['brandBlue.10', 'initial']}
borderRadius="10px"
>
<DeleteIcon
color="blue.500"
boxSize={5}
mt={['6px', 0]}
ml={['6px', 0]}
/>
</Box>
</WideLink>
</Stack>
</Stack>
</Stack>
<KillForm isOpen={isOpenKillForm} onClose={onCloseKillForm}></KillForm>
<ActivateInvitationDialog {...activateInviteDisclosure} />
<ReplenishStakeDrawer
{...replenishStakeDisclosure}
onSuccess={React.useCallback(
hash => {
toast({
title: t('Transaction sent'),
description: hash,
})
onCloseReplenishStakeDisclosure()
},
[onCloseReplenishStakeDisclosure, t, toast]
)}
onError={failToast}
/>
<SpoilInviteDrawer
{...spoilInviteDisclosure}
onSuccess={() => {
successToast(t('Invitation is successfully spoiled'))
spoilInviteDisclosure.onClose()
}}
onFail={failToast}
/>
</Page>
</Layout>
)
}
Example #7
Source File: create.js From idena-web with MIT License | 4 votes |
export default function CreateKey() {
const {t} = useTranslation()
const size = useBreakpointValue(['lg', 'md'])
const variant = useBreakpointValue(['mobile', 'initial'])
const buttonVariant = useBreakpointValue(['primaryFlat', 'secondary'])
const successToast = useSuccessToast()
const router = useRouter()
const [state, setState] = useState({
step: steps.AVATAR,
})
const [error, setError] = useState()
const {onCopy, hasCopied} = useClipboard(state.encryptedPrivateKey)
const setStep = s => setState(prevState => ({...prevState, step: s}))
const generateNewAddress = () => {
const key = generatePrivateKey()
setState(prevState => ({
...prevState,
privateKey: key,
address: privateKeyToAddress(key),
}))
}
const setPassword = () => {
if (state.password !== state.passwordConfirm) {
setError(t("Passwords don't match. Try again."))
} else {
const encryptedKey = encryptPrivateKey(state.privateKey, state.password)
setState(prevState => ({
...prevState,
encryptedPrivateKey: encryptedKey,
step: steps.BACKUP,
}))
setError(null)
}
}
useEffect(() => {
generateNewAddress()
}, [])
return (
<>
{state.step === steps.AVATAR && (
<AuthLayout>
<AuthLayout.Small>
<Flex width="100%" direction="column">
<Flex justifyContent="center">
<div style={{position: 'relative'}}>
<Avatar address={state.address} />
<Box
color={['xblack.016', 'xwhite.500']}
opacity={[1, '0.8']}
position="absolute"
w={8}
h={8}
bottom={['28px', '5px']}
right={['-40px', '5px']}
borderRadius="6px"
background="gray.500"
padding="3px 2px 2px 5px"
cursor="pointer"
onClick={() => generateNewAddress()}
>
<RefreshIcon
color={['xwhite.500', 'inherit']}
boxSize={5}
fill="white"
style={{
opacity: 0.8,
transform: 'scaleX(-1) rotate(90deg)',
}}
></RefreshIcon>
</Box>
</div>
</Flex>
<Flex mt={[5, 0]} justify="center">
<SubHeading color="white">{t('Your address')}</SubHeading>
</Flex>
<Flex
mt="5px"
mb="45px"
fontSize="mdx"
style={{
opacity: 0.5,
textAlign: 'center',
wordBreak: 'break-all',
}}
>
{state.address}
</Flex>
<PrimaryButton
size={size}
onClick={() => setStep(steps.PASSWORD)}
>
{t('Proceed')}
</PrimaryButton>
<Flex justifyContent="center">
<FlatButton onClick={() => router.push('/')} mt={5}>
{t('Cancel')}
</FlatButton>
</Flex>
</Flex>
</AuthLayout.Small>
</AuthLayout>
)}
{state.step === steps.PASSWORD && (
<AuthLayout>
<Box
w="100%"
h={6}
position="absolute"
top="40px"
display={['block', 'none']}
>
<ArrowBackIcon
fill="#fff"
boxSize={6}
ml={4}
onClick={() => setStep(steps.AVATAR)}
></ArrowBackIcon>
</Box>
<AuthLayout.Normal>
<Flex
direction={['column', 'initial']}
align={['center', 'initial']}
width="100%"
>
<Avatar address={state.address} />
<Flex
direction="column"
align={['center', 'initial']}
justify="center"
flex="1"
w={['75%', '100%']}
mt={[5, 0]}
ml={[0, 5]}
>
<Box>
<SubHeading color="white">
{t('Create password to encrypt your account')}
</SubHeading>
</Box>
<Flex justify="space-between">
<Text
wordBreak={['break-all', 'initial']}
color="xwhite.050"
fontSize="mdx"
>
{state.address}
</Text>
</Flex>
</Flex>
</Flex>
<Flex width="100%" mt={6}>
<form
onSubmit={e => {
e.preventDefault()
setPassword()
}}
style={{width: '100%'}}
>
<FormLabel
display={['none', 'inherit']}
htmlFor="key"
style={{color: 'white', fontSize: '13px'}}
>
{t('Password')}
</FormLabel>
<Flex width="100%" mb={[3, 5]} style={{position: 'relative'}}>
<PasswordInput
id="password"
size={size}
value={state.password}
width="100%"
borderColor="xblack.008"
backgroundColor="xblack.016"
onChange={e =>
setState({
...state,
password: e.target.value,
})
}
placeholder={t('Enter password')}
/>
</Flex>
<FormLabel
display={['none', 'inherit']}
htmlFor="key"
style={{
color: 'white',
fontSize: '13px',
}}
>
{t('Confirm password')}
</FormLabel>
<Flex width="100%" style={{position: 'relative'}}>
<PasswordInput
id="passwordConfirm"
size={size}
value={state.passwordConfirm}
width="100%"
borderColor="xblack.008"
backgroundColor="xblack.016"
onChange={e =>
setState({
...state,
passwordConfirm: e.target.value,
})
}
placeholder={t('Enter password again')}
/>
</Flex>
<Flex mt={[4, 8]} justify="space-between">
<FlatButton
display={['none', 'inherit']}
color="white"
_hover={{color: 'xwhite.080'}}
onClick={() => setStep(steps.AVATAR)}
>
<ArrowUpIcon
boxSize={5}
style={{transform: 'rotate(-90deg)', marginTop: -3}}
></ArrowUpIcon>
{t('Back')}
</FlatButton>
<PrimaryButton
size={size}
w={['100%', 'initial']}
type="submit"
>
{t('Next')}
</PrimaryButton>
</Flex>
{error && (
<Flex
mt="30px"
background="rgb(255, 102, 102)"
borderRadius="9px"
fontSize="mdx"
p="18px 24px"
>
{error}
</Flex>
)}
</form>
</Flex>
</AuthLayout.Normal>
</AuthLayout>
)}
{state.step === steps.BACKUP && (
<AuthLayout>
<Box
w="100%"
h={6}
position="absolute"
top="40px"
display={['block', 'none']}
>
<ArrowBackIcon
fill="#fff"
boxSize={6}
ml={4}
onClick={() => setStep(steps.PASSWORD)}
></ArrowBackIcon>
</Box>
<AuthLayout.Normal>
<Flex
direction={['column', 'initial']}
align={['center', 'initial']}
width="100%"
>
<Avatar address={state.address} />
<Flex
direction="column"
justify="center"
flex="1"
mt={[4, 0]}
ml={[0, 5]}
>
<SubHeading color="white">
{t('Backup your private key')}
</SubHeading>
<Flex justify="space-between">
<Text color="xwhite.050" fontSize="mdx">
{t(
'Make a photo of QR code or save your encrypted private key.'
)}
</Text>
</Flex>
</Flex>
</Flex>
<Flex width="100%" mt={6}>
<form
onSubmit={e => {
e.preventDefault()
if (!state.understand1 || !state.understand2) {
setError(t('Please confirm you understand risks'))
} else {
sendSignUp(state.address)
setError('')
setStep(steps.SUCCESS)
}
}}
style={{width: '100%'}}
>
<Flex display={['none', 'flex']} justify="space-between">
<FormLabel style={{color: 'white', fontSize: 'md'}}>
{t('Your encrypted private key')}
</FormLabel>
{hasCopied ? (
<FormLabel style={{color: 'white', fontSize: 'md'}}>
{t('Copied!')}
</FormLabel>
) : (
<FlatButton onClick={onCopy} marginBottom="10px">
{t('Copy')}
</FlatButton>
)}
</Flex>
<Flex width="100%" mb={[0, 5]} style={{position: 'relative'}}>
<Input
size={size}
variant={variant}
value={state.encryptedPrivateKey}
borderColor="xblack.008"
backgroundColor={['gray.500', 'xblack.016']}
width="100%"
pr={[10, 3]}
disabled
/>
<Box
display={['initial', 'none']}
position="absolute"
top={3}
right={3}
>
<CopyIcon
boxSize={6}
fill="#E8EAED"
opacity="0.16"
onClick={() => {
onCopy()
successToast({
title: 'Private key copied!',
duration: '5000',
})
}}
/>
</Box>
</Flex>
<Flex direction="column">
<Checkbox
order={[2, 1]}
mt={[9, 0]}
variant={variant}
textAlign={['left', 'initial']}
value={state.understand1}
isChecked={state.understand1}
onChange={e =>
setState({...state, understand1: e.target.checked})
}
style={{fontWeight: 300}}
>
{t(
'I understand that Idena cannot recover the private key for me.'
)}
</Checkbox>
<Checkbox
order={[3, 2]}
mt={2}
variant={variant}
textAlign={['left', 'initial']}
value={state.understand2}
isChecked={state.understand2}
onChange={e =>
setState({...state, understand2: e.target.checked})
}
style={{fontWeight: 300}}
>
{t(
'I understand the risk of compromising my private key backup.'
)}
</Checkbox>
<Flex order={[1, 3]} mt={[4, 8]} justify="space-between">
<FlatButton
display={['none', 'inherit']}
color="white"
_hover={{color: 'xwhite.080'}}
onClick={() => {
setError('')
setStep(steps.PASSWORD)
}}
>
<ArrowUpIcon
boxSize={5}
style={{transform: 'rotate(-90deg)', marginTop: -3}}
></ArrowUpIcon>
{t('Back')}
</FlatButton>
<Flex
w={['100%', 'initial']}
direction={['column', 'initial']}
>
<Button
order={[2, 1]}
size={size}
variant={buttonVariant}
w={['100%', 'initial']}
type="button"
mt={[4, 0]}
mr={[0, 2.5]}
fontSize={['15px', '13px']}
onClick={() => setState({...state, showQrDialog: true})}
>
{t('Show QR code')}
</Button>
<PrimaryButton
order={[1, 2]}
w={['100%', 'initial']}
size={size}
type="submit"
>
{t('Next')}
</PrimaryButton>
</Flex>
</Flex>
</Flex>
{error && (
<Flex
mt="30px"
p="18px 24px"
background="rgb(255, 102, 102)"
borderRadius="9px"
fontSyze="mdx"
style={{
fontSize: '14px',
}}
>
{error}
</Flex>
)}
</form>
</Flex>
</AuthLayout.Normal>
<Dialog
key="qr"
isOpen={state.showQrDialog}
onClose={() => setState({...state, showQrDialog: false})}
>
<DialogHeader>{t('Encrypted private key')}</DialogHeader>
<DialogBody>
{t('Scan QR by your mobile phone.')}
<Flex justify="center" mx="auto" my={8}>
<QRCode value={state.encryptedPrivateKey} />
</Flex>
</DialogBody>
<DialogFooter>
<SecondaryButton
onClick={() => setState({...state, showQrDialog: false})}
>
{t('Close')}
</SecondaryButton>
<PrimaryButton
onClick={() => {
const blob = new Blob([state.encryptedPrivateKey], {
type: 'text/plain;charset=utf-8',
})
saveAs(blob, 'idena-encrypted-key.txt')
}}
>
{t('Save to file')}
</PrimaryButton>
</DialogFooter>
</Dialog>
</AuthLayout>
)}
{state.step === steps.SUCCESS && (
<AuthLayout>
<AuthLayout.Small>
<Flex width="100%" direction="column">
<Flex justifyContent="center">
<div style={{position: 'relative'}}>
<Avatar address={state.address} />
</div>
</Flex>
<Flex justify="center" marginTop={7.5}>
<SubHeading color="white">
{t('Successfully created!')}
</SubHeading>
</Flex>
<Flex
mt="5px"
mb="45px"
fontSize="mdx"
style={{
opacity: 0.5,
textAlign: 'center',
wordBreak: 'break-all',
}}
>
{state.address}
</Flex>
<PrimaryButton
size={size}
onClick={() => router.push('/key/import')}
>
{t('Sign in')}
</PrimaryButton>
<Flex display={['none', 'flex']} justifyContent="center">
<FlatButton onClick={() => setStep(steps.BACKUP)} mt={5}>
{t('Back')}
</FlatButton>
</Flex>
</Flex>
</AuthLayout.Small>
</AuthLayout>
)}
</>
)
}
Example #8
Source File: affiliate.js From idena-web with MIT License | 4 votes |
export default function Affiliate() {
const {t} = useTranslation()
const {coinbase} = useAuthState()
const refLink = `app.idena.io?ref=${coinbase}`
const {onCopy: onCopyRef, hasCopied} = useClipboard(refLink)
const detailLinkTitle = useBreakpointValue([
'More details',
'More details about Idena affiliate program',
])
return (
<SettingsLayout title={t('Affilate program')}>
<Flex direction="column" mt={10} w={['100%', '480px']}>
<SubHeading fontSize={['20px', 'lg']} mb={4}>
{t('Idena affiliate program')}
</SubHeading>
<Text fontSize={['mdx', 'md']}>
{t(
'The program allows you to earn rewards for new validated identities you bring to the network.'
)}
</Text>
<FullSizeLink
label={detailLinkTitle}
href="https://docs.idena.io/docs/community/affiliate"
mt={[4, '3px']}
>
<Box boxSize={8} backgroundColor="brandBlue.10" borderRadius="10px">
<OpenExplorerIcon boxSize={5} mt="6px" ml="6px" />
</Box>
</FullSizeLink>
<UnorderedList mt={9} ml={[0, 4]}>
<UniversalListItem title="Apply for participation by submitting request form">
<SimpleLink href="https://forms.gle/1R1AKZokEYn3aUU19">
{t('Referral link request form')}
</SimpleLink>
</UniversalListItem>
<UniversalListItem title="Spread the word">
<Text>{t('Educate your community about Idena')}</Text>
</UniversalListItem>
<UniversalListItem title="Share your referral link">
<Box mt={2} mb={4} display={['block', 'none']}>
{hasCopied ? (
<FormLabel
position="absolute"
right={0}
top="1px"
fontSize="base"
color="green.500"
h={5}
m={0}
>
{t('Copied!')}
</FormLabel>
) : (
<FlatButton
position="absolute"
right={0}
top="2px"
fontSize="base"
fontWeight={500}
h={5}
onClick={onCopyRef}
>
{t('Copy')}
</FlatButton>
)}
<Input
size="lg"
textOverflow="ellipsis"
overflow="hidden"
whiteSpace="nowrap"
value={refLink}
width="100%"
disabled
/>
</Box>
<Text>
{t(
'Motivate your audience to join and help them to get an invite'
)}
</Text>
<Box
display={['none', 'block']}
mt={4}
px={10}
py={6}
backgroundColor="gray.50"
borderRadius="lg"
>
<Flex justify="space-between">
<Text color="muted">{t('Your Referral link')}</Text>
{hasCopied ? (
<FormLabel color="green.500" fontSize="md" m={0}>
{t('Copied!')}
</FormLabel>
) : (
<FlatButton fontWeight={500} onClick={onCopyRef}>
{t('Copy')}
</FlatButton>
)}
</Flex>
<Text
color="gray.500"
fontWeight={500}
wordBreak="break-all"
w="80%"
>
{refLink}
</Text>
</Box>
</UniversalListItem>
<UniversalListItem title="Help your invitees through the onboarding process">
<Text>
{t(
'Remind them about the validation ceremony and help them get validated'
)}
</Text>
</UniversalListItem>
<UniversalListItem isLast title="Get rewards">
<Trans t={t} i18nKey="affiliateFillRewards">
<Text>
Find the rewards you get and reward conditions on the{' '}
<SimpleLink href="https://docs.idena.io/docs/community/affiliate">
Idena affiliate program page
</SimpleLink>
</Text>
</Trans>
</UniversalListItem>
</UnorderedList>
</Flex>
</SettingsLayout>
)
}
Example #9
Source File: index.js From idena-web with MIT License | 4 votes |
function Settings() {
const router = useRouter()
const {t} = useTranslation()
const {lng, isoLng} = useLanguage()
const [password, setPassword] = useState()
const [showQR, setShowQR] = useState()
const {
isOpen: isOpenExportPKDialog,
onOpen: onOpenExportPKDialog,
onClose: onCloseExportPKDialog,
} = useDisclosure()
const changeLanguageDisclosure = useDisclosure()
const [pk, setPk] = useState('')
const {onCopy, hasCopied} = useClipboard(pk)
const {exportKey} = useAuthDispatch()
const size = useBreakpointValue(['lg', 'md'])
const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])
const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
const buttonWidth = useBreakpointValue(['100%', 'auto'])
const successToast = useSuccessToast()
const epochData = useEpoch()
const {coinbase} = useAuthState()
const {addError} = useNotificationDispatch()
const getLogs = async () => {
try {
const epoch = epochData.epoch - 1
const logs = await readValidationLogs(epoch)
const blob = new Blob(
[logs.map(x => `${x.timestamp} - ${JSON.stringify(x.log)}`).join('\n')],
{
type: 'text/plain;charset=utf-8',
}
)
saveAs(blob, `validation-${epoch}-${coinbase}.txt`)
} catch (e) {
addError({title: 'Cannot export logs', body: e.message})
}
}
return (
<SettingsLayout title={t('Settings')}>
<Language display={['none', 'block']} />
<ExportPK
display={['none', 'block']}
onDialogOpen={onOpenExportPKDialog}
/>
<ExportLogs display={['none', 'block']} getLogs={getLogs} />
<Flex display={['flex', 'none']} direction="column" mt={6}>
<MobileSettingsItem
title={t('Node')}
onClick={() => router.push('/settings/node')}
/>
<MobileSettingsItem
title={t('Affiliate program')}
onClick={() => router.push('/settings/affiliate')}
/>
<MobileSettingsItem
title={t('Language')}
description={`${isoLng} (${lng.toUpperCase()})`}
mb={6}
onClick={() => changeLanguageDisclosure.onOpen()}
/>
<WideLink
label={t('Export my private key')}
onClick={onOpenExportPKDialog}
>
<Box boxSize={8} backgroundColor="brandBlue.10" borderRadius="10px">
<PrivateKeyIcon fill="#578FFF" boxSize={5} mt="6px" ml="6px" />
</Box>
</WideLink>
<WideLink label={t('Export validation logs')} onClick={getLogs}>
<Box boxSize={8} backgroundColor="brandBlue.10" borderRadius="10px">
<OpenExplorerIcon boxSize={5} mt="6px" ml="6px" />
</Box>
</WideLink>
</Flex>
<Dialog
size="mdx"
isOpen={isOpenExportPKDialog}
onClose={onCloseExportPKDialog}
>
<DialogHeader>{t('Encrypted private key')}</DialogHeader>
<DialogBody mb={0}>
{!showQR ? (
<form
onSubmit={e => {
e.preventDefault()
const key = exportKey(password)
setPk(key)
setShowQR(true)
}}
>
<Flex direction="column" align="flex-start">
<Text fontSize="mdx" color="gray.300">
{t('Create a new password to export your private key')}
</Text>
<FormLabel
fontSize={['base', 'md']}
mt={5}
mb={3}
w={['auto', '100px']}
htmlFor="url"
>
{t('New password')}
</FormLabel>
<PasswordInput
size={size}
value={password}
mr={[0, '15px']}
width="100%"
disabled={showQR}
onChange={e => setPassword(e.target.value)}
/>
</Flex>
<Flex mt={6} justify="flex-end">
<Button
variant={variantSecondary}
size={size}
w={buttonWidth}
onClick={onCloseExportPKDialog}
>
{t('Close')}
</Button>
<Button
variant={variantPrimary}
size={size}
ml={[0, 2]}
w={buttonWidth}
type="submit"
disabled={!password}
>
{t('Export')}
</Button>
</Flex>
</form>
) : (
<Box>
<Text>
{t(
'Scan QR by your mobile phone or copy code below for export privatekey.'
)}
</Text>
<Flex justify="center" mx="auto" my={8}>
<QRCode value={pk} />
</Flex>
<Flex display={['none', 'flex']} justify="space-between">
<FormLabel style={{fontSize: rem(13)}}>
{t('Your encrypted private key')}
</FormLabel>
{hasCopied ? (
<FormLabel style={{fontSize: rem(13)}}>
{t('Copied!')}
</FormLabel>
) : (
<FlatButton onClick={onCopy} marginBottom={rem(10)}>
{t('Copy')}
</FlatButton>
)}
</Flex>
<Flex
width="100%"
style={{marginBottom: rem(20), position: 'relative'}}
>
<Input
size={size}
value={pk}
width="100%"
pr={[10, 0]}
disabled
/>
<Box
display={['initial', 'none']}
position="absolute"
top={3}
right={3}
>
<CopyIcon
boxSize={6}
fill="muted"
opacity="0.4"
onClick={() => {
onCopy()
successToast({
title: t('Private key copied!'),
duration: '5000',
})
}}
/>
</Box>
</Flex>
<Flex justify="flex-end">
<Button
variant={variantSecondary}
size={size}
w={buttonWidth}
onClick={() => {
setPassword('')
setShowQR(false)
onCloseExportPKDialog()
}}
>
{t('Close')}
</Button>
</Flex>
</Box>
)}
</DialogBody>
</Dialog>
<ChangeLanguageDrawer
changeLanguageDisclosure={changeLanguageDisclosure}
/>
</SettingsLayout>
)
}
Example #10
Source File: containers.js From idena-web with MIT License | 4 votes |
export function ContactCard({
contact,
onEditContact,
onRemoveContact,
onRecoverContact,
onKillContact,
onInviteMined,
}) {
const {
t,
i18n: {language},
} = useTranslation()
const [{invites}, {deleteInvite, recoverInvite}] = useInvite()
const invitee = invites.find(byId(contact))
const {
id,
key,
receiver,
address = receiver,
firstName,
lastName,
canKill,
mining,
terminating,
activated,
identity: {state, stake} = {},
} = {...contact, ...invitee}
const {onCopy: onCopyKey, hasCopied} = useClipboard(key)
const successToast = useSuccessToast()
React.useEffect(() => {
if (state === IdentityStatus.Invite) {
onInviteMined()
}
}, [onInviteMined, state])
const isInviteExpired =
state === IdentityStatus.Undefined && !canKill && !mining && !activated
const status = isInviteExpired
? t('Expired invitation')
: mining
? t('Mining...')
: terminating
? t('Terminating...')
: state === IdentityStatus.Invite
? t('Invitation')
: mapToFriendlyStatus(state) ?? 'Unknown'
const toDna = toLocaleDna(language)
return (
<>
<Stack spacing={6} w="full">
<Stack spacing={4}>
<Stack isInline spacing={6} align="center" py={2}>
<ContactAvatar address={address} borderRadius={20} />
<Stack spacing={1.5} fontWeight={500}>
<Stack isInline align="center">
<Text fontSize="lg">
{`${firstName} ${lastName}`.trim() || t('...')}
</Text>
{mining && (
<ContactCardBadge bg="orange.010" color="orange.500">
{t('Mining...')}
</ContactCardBadge>
)}
{terminating && (
<ContactCardBadge bg="red.010" color="red.500">
{t('Terminating...')}
</ContactCardBadge>
)}
</Stack>
<Text color="muted" fontSize="mdx" wordBreak="break-all">
{address}
</Text>
</Stack>
</Stack>
<Stack isInline align="center" spacing={1} w="full">
<IconButton icon={<EditIcon boxSize={5} />} onClick={onEditContact}>
{t('Edit')}
</IconButton>
<VDivider />
<Tooltip label={t('Remove from device')}>
<IconButton
icon={<BasketIcon boxSize={5} />}
onClick={() => {
deleteInvite(id)
successToast({
title: t('Contact deleted'),
onAction: () => {
recoverInvite(id)
onRecoverContact(contact)
},
actionContent: t('Undo'),
})
onRemoveContact()
}}
>
{t('Delete contact')}
</IconButton>
</Tooltip>
{canKill && !terminating && !mining && (
<>
<VDivider />
<IconButton
icon={<DeleteIcon boxSize={5} />}
colorScheme="red"
_active={{
bg: 'red.012',
}}
_focus={{
boxShadow: '0 0 0 3px rgb(255 102 102 /0.50)',
}}
onClick={onKillContact}
>
{t('Terminate invitation')}
</IconButton>
</>
)}
</Stack>
</Stack>
<Stack spacing={5} bg="gray.50" px={10} py={8} borderRadius="md">
<Stack spacing={0}>
{state !== IdentityStatus.Invite && !isInviteExpired && !mining && (
<ContactStat label={t('Address')} value={receiver} />
)}
<ContactStat label={t('Status')} value={status} pt={2} pb={3} />
{stake > 0 && <ContactStat label="Stake" value={toDna(stake)} />}
</Stack>
{!isInviteExpired && !activated && (
<FormControl>
<Stack spacing={3}>
<Flex align="center" justify="space-between">
<FormLabel pb={0}>{t('Invitation code')}</FormLabel>
{!activated &&
(hasCopied ? (
<FormLabel color="green.500" fontSize="md" m={0}>
{t('Copied!')}
</FormLabel>
) : (
<FlatButton onClick={onCopyKey}>{t('Copy')}</FlatButton>
))}
</Flex>
<Input label={t('Invitation code')} value={key} isDisabled />
</Stack>
</FormControl>
)}
</Stack>
</Stack>
</>
)
}
Example #11
Source File: components.js From idena-web with MIT License | 4 votes |
export function ActivateMiningDrawer({
mode,
delegationEpoch,
pendingUndelegation,
currentEpoch,
isLoading,
onChangeMode,
onActivate,
onClose,
...props
}) {
const {t} = useTranslation()
const [delegatee, setDelegatee] = useState(pendingUndelegation)
const {onCopy, hasCopied} = useClipboard('https://www.idena.io/download')
const sizeInput = useBreakpointValue(['lg', 'md'])
const sizeButton = useBreakpointValue(['mdx', 'md'])
const variantRadio = useBreakpointValue(['mobile', 'bordered'])
const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])
const waitForDelegationEpochs =
3 - (currentEpoch - delegationEpoch) <= 0
? 3
: 3 - (currentEpoch - delegationEpoch)
return (
<AdDrawer isMining={isLoading} onClose={onClose} {...props}>
<DrawerHeader>
<Flex
direction="column"
textAlign={['center', 'start']}
justify={['space-between', 'flex-start']}
>
<Flex
order={[2, 1]}
mt={[6, 0]}
align="center"
justify="center"
bg="blue.012"
h={12}
w={12}
rounded="xl"
>
<UserIcon boxSize={6} color="blue.500" />
</Flex>
<Heading
order={[1, 2]}
color="brandGray.500"
fontSize={['base', 'lg']}
fontWeight={[['bold', 500]]}
lineHeight="base"
mt={[0, 4]}
>
{t('Miner status')}
</Heading>
</Flex>
</DrawerHeader>
<DrawerBody>
<Stack spacing={[6]} mt={[0, 30]}>
<FormControl as={Stack} spacing={[1, 3]}>
<FormLabel
fontSize={['11px', '13px']}
fontWieght={['400!important', '500']}
color={['muted', 'initial']}
mb={[0, 2]}
p={0}
>
{t('Type')}
</FormLabel>
<RadioGroup
isInline
d="flex"
flexDirection={['column', 'row']}
value={mode}
onChange={onChangeMode}
>
<Radio
variant={variantRadio}
value={NodeType.Miner}
flex={['0 0 56px', 1]}
fontSize={['base', 'md']}
fontWeight={['500', '400']}
px={[4, 2]}
py={['18px', 2]}
mr={2}
>
{t('Mining')}
</Radio>
<Radio
variant={variantRadio}
value={NodeType.Delegator}
flex={['0 0 56px', 1]}
fontSize={['base', 'md']}
fontWeight={['500', '400']}
px={[4, 2]}
py={['18px', 2]}
>
{t('Delegation')}
</Radio>
</RadioGroup>
</FormControl>
{mode === NodeType.Delegator ? (
<Stack spacing={5}>
<FormControl as={Stack} spacing={[0, 3]}>
<FormLabel fontSize={['base', 'md']}>
{t('Delegation address')}
</FormLabel>
<Input
size={sizeInput}
value={delegatee}
isDisabled={Boolean(pendingUndelegation)}
onChange={e => setDelegatee(e.target.value)}
/>
</FormControl>
{pendingUndelegation ? (
<ErrorAlert>
{t(
'You have recently disabled delegation. You need to wait for {{count}} epochs to delegate to a new address.',
{count: waitForDelegationEpochs}
)}
</ErrorAlert>
) : (
<ErrorAlert alignItems="start" pb="3">
<Stack>
<Text>
{t(
'You can lose your stake, all your mining and validation rewards if you delegate your mining status.'
)}
</Text>
<Text>
{t('You can disable delegation at the next epoch only.')}
</Text>
</Stack>
</ErrorAlert>
)}
</Stack>
) : (
<Stack spacing={[4, 5]}>
<Text fontSize={['mdx', 'md']} mb={[0, 3]}>
{t(
'To activate mining status please download the desktop version of Idena app'
)}
</Text>
<Flex
borderY={[0, '1px']}
h={16}
alignItems="center"
justifyContent="space-between"
sx={{
'&': {
borderColor: 'gray.100',
},
}}
>
<Flex w={['100%', 'auto']}>
<Stack
w={['100%', 'auto']}
spacing={[4, 2]}
isInline
align="center"
color="brand.gray"
>
<Flex
shrink={0}
boxSize={[8, 5]}
align="center"
justify="center"
backgroundColor={['brandGray.012', 'initial']}
borderRadius="10px"
>
<LaptopIcon boxSize={5} />
</Flex>
<Flex
direction="row"
w={['100%', 'auto']}
justify={['space-between', 'flex-start']}
borderBottom={['1px', 0]}
borderColor="gray.100"
lineHeight={['48px', 'auto']}
>
<Text as="span" fontSize={['base', 14]} fontWeight={500}>
{t('Desktop App')}
</Text>
{hasCopied ? (
<Text
display={['block', 'none']}
as="span"
color="green.500"
fontSize="base"
fontWeight={500}
>
{t('Copied')}
</Text>
) : (
<FlatButton
display={['block', 'none']}
onClick={onCopy}
fontWeight="500"
>
{t('Copy link')}
</FlatButton>
)}
</Flex>
</Stack>
</Flex>
<Flex display={['none', 'flex']}>
<Link
href="https://www.idena.io/download"
target="_blank"
color="brandBlue.500"
rounded="md"
fontWeight={500}
fontSize={13}
>
{t('Download')}
</Link>
</Flex>
</Flex>
<Flex
rounded="md"
bg="gray.50"
borderColor="gray.50"
borderWidth={1}
px={6}
py={4}
>
<Text color="muted" fontSize={['mdx', 'md']} lineHeight="20px">
{t(
'Use your private key backup to migrate your account. You can import your private key backup at the Settings page in Idena Desktop app.'
)}
</Text>
</Flex>
</Stack>
)}
</Stack>
<PrimaryButton
display={['flex', 'none']}
mt={4}
w="100%"
fontSize="mobile"
size="lg"
isDisabled={mode === NodeType.Miner}
isLoading={isLoading}
onClick={() => {
onActivate({delegatee})
}}
loadingText={t('Waiting...')}
>
{t('Submit')}
</PrimaryButton>
</DrawerBody>
<DrawerFooter display={['none', 'flex']} mt={[6, 0]} px={0}>
<Flex width="100%" justify={['space-evenly', 'flex-end']}>
<Button
variant={variantSecondary}
order={[3, 1]}
size={sizeButton}
type="button"
onClick={onClose}
>
{t('Cancel')}
</Button>
<Divider
order="2"
display={['block', 'none']}
h={10}
orientation="vertical"
color="gray.100"
/>
<Button
variant={variantPrimary}
order={[1, 3]}
size={sizeButton}
ml={[0, 2]}
isDisabled={mode === NodeType.Miner}
isLoading={isLoading}
onClick={() => {
onActivate({delegatee})
}}
loadingText={t('Waiting...')}
>
{t('Submit')}
</Button>
</Flex>
</DrawerFooter>
</AdDrawer>
)
}
Example #12
Source File: BuilderProfileCard.jsx From scaffold-directory with MIT License | 4 votes |
BuilderProfileCard = ({ builder, mainnetProvider, isMyProfile, userProvider, fetchBuilder, userRole }) => {
const address = useUserAddress(userProvider);
const ens = useDisplayAddress(mainnetProvider, builder?.id);
const [updatedSocials, setUpdatedSocials] = useState({});
const [isUpdatingReachedOutFlag, setIsUpdatingReachedOutFlag] = useState(false);
const [isUpdatingSocials, setIsUpdatingSocials] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const { hasCopied, onCopy } = useClipboard(builder?.id);
const { borderColor, secondaryFontColor } = useCustomColorModes();
const shortAddress = ellipsizedAddress(builder?.id);
const hasEns = ens !== shortAddress;
const toast = useToast({ position: "top", isClosable: true });
const toastVariant = useColorModeValue("subtle", "solid");
const joinedDate = new Date(builder?.creationTimestamp);
const joinedDateDisplay = joinedDate.toLocaleString("default", { month: "long" }) + " " + joinedDate.getFullYear();
// INFO: conditional chaining and coalescing didn't work when also checking the length
const hasProfileLinks = builder?.socialLinks ? Object.keys(builder.socialLinks).length !== 0 : false;
const isAdmin = userRole === USER_ROLES.admin;
useEffect(() => {
if (builder) {
setUpdatedSocials(builder.socialLinks ?? {});
}
}, [builder]);
const handleUpdateSocials = async () => {
setIsUpdatingSocials(true);
// Avoid sending socials with empty strings.
const socialLinkCleaned = Object.fromEntries(Object.entries(updatedSocials).filter(([_, value]) => !!value));
const invalidSocials = validateSocials(socialLinkCleaned);
if (invalidSocials.length !== 0) {
toast({
description: `The usernames for the following socials are not correct: ${invalidSocials
.map(([social]) => social)
.join(", ")}`,
status: "error",
variant: toastVariant,
});
setIsUpdatingSocials(false);
return;
}
let signMessage;
try {
signMessage = await getUpdateSocialsSignMessage(address);
} catch (error) {
toast({
description: " Sorry, the server is overloaded. ???",
status: "error",
variant: toastVariant,
});
setIsUpdatingSocials(false);
return;
}
let signature;
try {
signature = await userProvider.send("personal_sign", [signMessage, address]);
} catch (error) {
toast({
description: "Couldn't get a signature from the Wallet",
status: "error",
variant: toastVariant,
});
setIsUpdatingSocials(false);
return;
}
try {
await postUpdateSocials(address, signature, socialLinkCleaned);
} catch (error) {
if (error.status === 401) {
toast({
status: "error",
description: "Access error",
variant: toastVariant,
});
setIsUpdatingSocials(false);
return;
}
toast({
status: "error",
description: "Can't update your socials. Please try again.",
variant: toastVariant,
});
setIsUpdatingSocials(false);
return;
}
toast({
description: "Your social links have been updated",
status: "success",
variant: toastVariant,
});
fetchBuilder();
setIsUpdatingSocials(false);
onClose();
};
const handleUpdateReachedOutFlag = async reachedOut => {
setIsUpdatingReachedOutFlag(true);
let signMessage;
try {
signMessage = await getUpdateReachedOutFlagSignMessage(builder.id, reachedOut);
} catch (error) {
toast({
description: " Sorry, the server is overloaded. ???",
status: "error",
variant: toastVariant,
});
setIsUpdatingReachedOutFlag(false);
return;
}
let signature;
try {
signature = await userProvider.send("personal_sign", [signMessage, address]);
} catch (error) {
toast({
description: "Couldn't get a signature from the Wallet",
status: "error",
variant: toastVariant,
});
setIsUpdatingReachedOutFlag(false);
return;
}
try {
await postUpdateReachedOutFlag(address, builder.id, reachedOut, signature);
} catch (error) {
if (error.status === 401) {
toast({
status: "error",
description: "Access error",
variant: toastVariant,
});
setIsUpdatingReachedOutFlag(false);
return;
}
toast({
status: "error",
description: "Can't update the reached out flag. Please try again.",
variant: toastVariant,
});
setIsUpdatingReachedOutFlag(false);
return;
}
toast({
description: 'Updated "reached out" flag successfully',
status: "success",
variant: toastVariant,
});
fetchBuilder();
setIsUpdatingReachedOutFlag(false);
};
return (
<>
<BuilderProfileCardSkeleton isLoaded={!!builder}>
{() => (
/* delay execution */
<Flex
borderRadius="lg"
borderColor={borderColor}
borderWidth={1}
justify={{ base: "space-around", xl: "center" }}
direction={{ base: "row", xl: "column" }}
p={4}
pb={6}
maxW={{ base: "full", lg: "50%", xl: 60 }}
margin="auto"
>
<Link as={RouteLink} to={`/builders/${builder.id}`}>
<QRPunkBlockie
withQr={false}
address={builder.id?.toLowerCase()}
w={52}
borderRadius="lg"
margin="auto"
/>
</Link>
<Flex alignContent="center" direction="column" mt={4}>
{hasEns ? (
<>
<Text fontSize="2xl" fontWeight="bold" textAlign="center">
{ens}
</Text>
<Text textAlign="center" mb={4} color={secondaryFontColor}>
{shortAddress}{" "}
<Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
<CopyIcon cursor="pointer" onClick={onCopy} />
</Tooltip>
</Text>
</>
) : (
<Text fontSize="2xl" fontWeight="bold" textAlign="center" mb={8}>
{shortAddress}{" "}
<Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
<CopyIcon cursor="pointer" onClick={onCopy} />
</Tooltip>
</Text>
)}
{isAdmin && (
<Center mb={4}>
{builder.reachedOut ? (
<Badge variant="outline" colorScheme="green" alignSelf="center">
Reached Out
</Badge>
) : (
<Button
colorScheme="green"
size="xs"
onClick={() => handleUpdateReachedOutFlag(true)}
isLoading={isUpdatingReachedOutFlag}
alignSelf="center"
>
Mark as reached out
</Button>
)}
</Center>
)}
<Divider mb={6} />
{hasProfileLinks ? (
<Flex mb={4} justifyContent="space-evenly" alignItems="center">
{Object.entries(builder.socialLinks)
.sort(bySocialWeight)
.map(([socialId, socialValue]) => (
<SocialLink id={socialId} value={socialValue} />
))}
</Flex>
) : (
isMyProfile && (
<Alert mb={3} status="warning">
<Text style={{ fontSize: 11 }}>
You haven't set your socials{" "}
<Tooltip label="It's our way of reaching out to you. We could sponsor you an ENS, offer to be part of a build or set up an ETH stream for you.">
<QuestionOutlineIcon />
</Tooltip>
</Text>
</Alert>
)
)}
{isMyProfile && (
<Button mb={3} size="xs" variant="outline" onClick={onOpen}>
Update socials
</Button>
)}
<Text textAlign="center" color={secondaryFontColor}>
Joined {joinedDateDisplay}
</Text>
</Flex>
</Flex>
)}
</BuilderProfileCardSkeleton>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Update your socials</ModalHeader>
<ModalCloseButton />
<ModalBody p={6}>
{Object.entries(socials).map(([socialId, socialData]) => (
<FormControl id="socialId" key={socialId} mb={3}>
<FormLabel htmlFor={socialId} mb={0}>
<strong>{socialData.label}:</strong>
</FormLabel>
<Input
type="text"
name={socialId}
value={updatedSocials[socialId] ?? ""}
placeholder={socialData.placeholder}
onChange={e => {
const value = e.target.value;
setUpdatedSocials(prevSocials => ({
...prevSocials,
[socialId]: value,
}));
}}
/>
</FormControl>
))}
<Button colorScheme="blue" onClick={handleUpdateSocials} isLoading={isUpdatingSocials} isFullWidth mt={4}>
Update
</Button>
</ModalBody>
</ModalContent>
</Modal>
</>
);
}