react-use#useToggle TypeScript Examples
The following examples show how to use
react-use#useToggle.
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: LiquidityMessage.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
LiquidityMessageContent: FC<{
vault: BoostedVaultState
apy?: number
}> = ({ vault, apy }) => {
const [showCalculator, setShowCalculator] = useToggle(false)
const network = useNetwork()
const canBoost = network.chainId === ChainIds.EthereumMainnet
return (
<TransitionCard
selection={showCalculator ? 'boost' : undefined}
components={{
boost: <BoostCalculator vault={vault} noBackButton apy={apy} />,
}}
>
<Container>
<div>
<h3>Need {vault?.stakingToken.symbol} tokens to stake?</h3>
<p>Provide liquidity by depositing below, and stake to earn rewards and trade fees</p>
</div>
<div>
{canBoost && (
<Button highlighted onClick={setShowCalculator}>
Calculate Boost
</Button>
)}
</div>
</Container>
</TransitionCard>
)
}
Example #2
Source File: layout.tsx From platyplus with MIT License | 6 votes |
Layout: React.FC<{ logo?: ReactNode menu?: ReactNode statusMenu?: ReactNode }> = ({ logo = <Logo />, menu, statusMenu, children }) => { const [collapsed, toggle] = useToggle(false) const hasSideMenu = !!menu return ( <ThemeProvider theme={theme}> <Container className="app"> {hasSideMenu && ( <SideMenu logo={logo} toggle={toggle} collapsed={collapsed}> {menu} </SideMenu> )} <Container> <Header statusMenu={statusMenu} collapsed={collapsed} toggle={toggle} sideMenu={hasSideMenu} /> <StyledContent>{children}</StyledContent> </Container> </Container> </ThemeProvider> ) }
Example #3
Source File: CollapseBox.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
CollapseBox: FC<{ title: string; className?: string }> = ({ children, title, className }) => {
const [collapsed, toggleCollapsed] = useToggle(true)
return (
<Container className={className}>
<Button onClick={toggleCollapsed}>
<div>{title}</div>
<Chevron direction={collapsed ? 'down' : 'up'} />
</Button>
<Content collapsed={collapsed}>{children}</Content>
</Container>
)
}
Example #4
Source File: index.ts From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
createToggleContext = (
defaultInitialValue = false,
): Readonly<[() => Toggle, FC<{ initialValue?: boolean }>, Context<Toggle>]> => {
const context = createContext<Toggle>(undefined as never)
const ToggleProvider: FC<{ initialValue?: boolean }> = ({ children, initialValue }) => {
const toggle = useToggle(initialValue !== undefined ? initialValue : defaultInitialValue)
return providerFactory(context, { value: toggle }, children)
}
return [createUseContextFn(context, true), ToggleProvider, context] as const
}
Example #5
Source File: GraphButton.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
GraphButton: FC = () => {
const container = useRef(null)
const networkStatus = useNetworkStatus()
const [show, toggleShow] = useToggle(false)
const items = Object.entries(networkStatus).filter(
([, status]) => status.numPendingQueries || status.numPendingMutations || status.queryError || status.mutationError,
)
return (
<Container
ref={container}
open={show}
pending={Object.values(networkStatus).some(status => status.numPendingQueries || status.numPendingMutations)}
error={Object.values(networkStatus).some(status => status.queryError || status.mutationError)}
>
<UnstyledButton onClick={toggleShow}>
<GraphQLIcon />
<div className="badge" />
</UnstyledButton>
<div className="items">
{items.length
? items.map(([endpointName, status]) => <EndpointStatus endpointName={endpointName} status={status} key={endpointName} />)
: 'No active queries'}
</div>
</Container>
)
}
Example #6
Source File: Dropdown.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
NavigationDropdown: FC<{ navItems: { title: string; path: string }[] }> = ({ navItems }) => {
const location = useLocation()
const [show, toggleShow] = useToggle(false)
const handleSelect = (): void => {
toggleShow(false)
}
const container = useRef(null)
useOnClickOutside(container, () => {
toggleShow(false)
})
const selected = navItems.find(item => location.pathname.startsWith(item.path))
return (
<NavContainer ref={container}>
<Option
onClick={() => {
toggleShow()
}}
optionName={selected?.title}
isDropdown
selected
active={show}
/>
<OptionList hidden={!show}>
{navItems
.filter(item => item.path !== selected?.path)
.map(item => (
<NavigationOption title={item.title} path={item.path} onClick={handleSelect} key={item.path} />
))}
</OptionList>
</NavContainer>
)
}
Example #7
Source File: Withdraw.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
Withdraw: FC<{ isLowLiquidity?: boolean }> = ({ isLowLiquidity = false }) => {
const [isRedeemExact, setRedeemExact] = useToggle(false)
const feederPool = useSelectedFeederPoolState()
const assets = useSelectedFeederPoolAssets()
return (
<MultiAssetExchangeProvider assets={assets}>
{isRedeemExact ? <RedeemExact /> : <RedeemLP />}
<RedeemPathBox>
<div>
<UnstyledButton onClick={setRedeemExact}>
{isLowLiquidity
? `Withdraw from ${isRedeemExact ? `${feederPool.token.symbol} Vault` : feederPool.token.symbol}`
: `Switch to ${isRedeemExact ? feederPool.token.symbol : 'exact'} amount redemption`}
</UnstyledButton>
</div>
</RedeemPathBox>
</MultiAssetExchangeProvider>
)
}
Example #8
Source File: EthereumPool.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
HeaderCharts: FC<{ color: string }> = ({ color }) => {
const [isLiquidity, toggleIsLiquidity] = useToggle(true)
return (
<HeaderChartsContainer>
<div>{isLiquidity ? <LiquidityChart color={color} /> : <PoolComposition />}</div>
<div>
<h3>{isLiquidity ? 'Liquidity' : 'Pool Composition'}</h3>
<Button onClick={toggleIsLiquidity}>{isLiquidity ? '↩' : '↪'}</Button>
</div>
</HeaderChartsContainer>
)
}
Example #9
Source File: Deposit.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
Deposit: FC<{ isLowLiquidity?: boolean }> = ({ isLowLiquidity = false }) => {
const [isMintExact, setMintExact] = useToggle(isLowLiquidity)
const feederPool = useSelectedFeederPoolState()
const assets = useSelectedFeederPoolAssets()
return (
<MultiAssetExchangeProvider assets={assets}>
{isMintExact ? <MintExact /> : <MintLP />}
<MintPathBox protip={isLowLiquidity}>
{isLowLiquidity ? (
<UnstyledButton disabled>Single-asset deposits are disabled due to low liquidity</UnstyledButton>
) : (
<UnstyledButton onClick={setMintExact}>
{`Switch to mint via ${isMintExact ? feederPool.token.symbol : 'multiple'} `}
</UnstyledButton>
)}
</MintPathBox>
</MultiAssetExchangeProvider>
)
}
Example #10
Source File: ClaimForm.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
ClaimForm: FC = () => {
const { selected: stakedTokenAddress, options } = useStakedToken()
const [isCompounding, toggleIsCompounding] = useToggle(false)
const stakedTokenSymbol = options[stakedTokenAddress]?.icon?.symbol
return (
<Container>
<ClaimFormRewards />
{stakedTokenSymbol === 'MTA' ? (
<Compound>
<div>
<h3>Compound rewards?</h3>
<ToggleInput onClick={toggleIsCompounding} checked={isCompounding} />
</div>
<p>This will claim and re-stake your earned MTA in 1 transaction</p>
</Compound>
) : (
<MerkleDropBAL />
)}
<ClaimFormSend isCompounding={isCompounding} />
</Container>
)
}
Example #11
Source File: StakeForms.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
Content: FC = () => {
const [{ tabs, activeTabIndex }, setActiveIndex] = useTabs()
const { data, loading } = useStakedTokenQuery()
const urlQuery = useURLQuery()
const [skipMigration, setSkipMigration] = useToggle(false)
const balanceV2Simple =
data?.stakedToken?.accounts?.[0]?.balance?.rawBD?.simple + parseFloat(data?.stakedToken?.accounts?.[0]?.balance?.cooldownUnits) / 1e18
const { hasWithdrawnV1Balance, hasSelectedStakeOption, lockedV1 } = useStakingStatus()
const migrateSlug = urlQuery.get('migrate') === 'true' // ?migrate=true
const { balance: balanceV1 } = lockedV1?.value ?? {}
const userNeedsMigration = (!!balanceV1?.simple && !balanceV2Simple) || hasWithdrawnV1Balance
const { Graph, Form, heading, subheading, link } = stakeTabs[activeTabIndex]
if (loading)
return (
<Empty>
<ThemedSkeleton />
</Empty>
)
return (userNeedsMigration || migrateSlug) && !skipMigration ? (
<StakeMigration onSkip={setSkipMigration} />
) : !hasSelectedStakeOption && !balanceV2Simple ? (
<StakeSelection />
) : (
<FormsContainer>
<GraphContainer>
<h2>{heading}</h2>
<h4>
{subheading} {link && <Link to={link.href}>{link.title}</Link>}
</h4>
<Graph />
</GraphContainer>
<FormContainer>
<TabsOfTruth tabs={tabs} activeTabIndex={activeTabIndex} setActiveIndex={setActiveIndex} />
<Form />
</FormContainer>
</FormsContainer>
)
}
Example #12
Source File: EthereumPool.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
PoolDetailContent: FC = () => {
const { address, title, liquidity, vault, poolType } = useSelectedFeederPoolState() as FeederPoolState
const massetPrice = useSelectedMassetPrice()
const network = useNetwork()
const isEthereum = network.chainId === ChainIds.EthereumMainnet
const [readMore, setReadMore] = useToggle(false)
const color = assetColorMapping[title]
const isLowLiquidity = massetPrice ? liquidity.simple * (massetPrice.value ?? 0) < 100000 : false
const tabs = useMemo(() => {
const tabs = {
Deposit: {
title: 'Deposit',
component: <Deposit isLowLiquidity={isLowLiquidity} />,
},
Withdraw: {
title: 'Withdraw',
component: <Withdraw isLowLiquidity={isLowLiquidity} />,
},
}
if (poolType === PoolType.Deprecated) {
delete tabs['Deposit']
}
return tabs
}, [isLowLiquidity, poolType])
const [activeTab, setActiveTab] = useState<string>(poolType === PoolType.Deprecated ? 'Withdraw' : 'Deposit')
return (
<RewardStreamsProvider vault={vault}>
<Container>
<PageHeader title="Pools" subtitle={title} massetSwitcher />
<HeaderContainer>
<PoolDetailCard poolAddress={address} />
<HeaderCharts color={color} />
</HeaderContainer>
<AssetDetails />
<PoolOverview />
<Exchange>
<TabCard tabs={tabs} active={activeTab} onClick={setActiveTab} />
<InfoBox highlight subtitle="Using mStable Feeder Pools">
<p>
Feeder Pools offer a way to earn with your assets with <span>low impermanent loss risk.</span>
</p>
<p>
Liquidity providers passively earn swap fees. Deposits to the Vault earn swap fees in addition to{' '}
{isEthereum ? `MTA rewards which vest over time.` : `token rewards.`}
{isEthereum && !readMore && <UnstyledButton onClick={setReadMore}>Learn more</UnstyledButton>}
</p>
{readMore && (
<>
<p>
You can <span>multiply your rewards</span> in mStable pools by staking MTA.
</p>
<p>
Claiming rewards will send 33% of the unclaimed amount to you immediately, with the rest safely locked in a stream vesting
linearly and finishing 26 weeks from the time at which you claimed.
</p>
<p>When streams are unlocked, these rewards are sent to you in full along with unclaimed earnings.</p>
</>
)}
</InfoBox>
</Exchange>
</Container>
</RewardStreamsProvider>
)
}
Example #13
Source File: Header.tsx From storefront with MIT License | 5 votes |
Header: React.VFC = () => {
const styles = useStyles();
const { settings } = useSettings();
const [open, toggleOpen] = useToggle(false);
const { data: menu } = useMenuQuery({
variables: { location: MenuLocationEnum.PRIMARY_NAVIGATION },
});
const { data: { cart } = { cart: undefined } } = useCartQuery({
fetchPolicy: 'no-cache',
ssr: false,
});
return (
<AppBar color="default" position="relative">
<Toolbar
className={styles.toolbar}
sx={{
minHeight: { xs: 60, md: 110 },
mx: 'auto',
width: '100%',
}}
>
<Box sx={{ display: { md: 'none' }, flexGrow: 1 }}>
<IconButton aria-label="Menu" onClick={toggleOpen}>
<Menu />
</IconButton>
</Box>
<Link href="/" underline="none">
<Logo className={styles.logo} aria-label={settings.title} />
</Link>
<Box
sx={{
alignItems: 'center',
alignSelf: 'stretch',
display: 'flex',
flexGrow: 1,
justifyContent: 'flex-end',
}}
>
<Box sx={{ display: { xs: 'none', md: 'flex' }, height: '100%' }}>
<HeaderMenu menu={menu} />
</Box>
<IconButton href="/cart" color="inherit" aria-label="Cart">
<Badge badgeContent={cart?.contents?.itemCount}>
<Cart />
</Badge>
</IconButton>
</Box>
</Toolbar>
<Collapse unmountOnExit in={open} timeout="auto">
<HeaderMenu menu={menu} />
</Collapse>
</AppBar>
);
}
Example #14
Source File: Dropdown.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
Dropdown: FC<Props> = ({ defaultOption, options = {}, onChange, disabled, className }) => {
const [show, toggleShow] = useToggle(false)
const container = useRef(null)
const selected = useMemo(
() => Object.keys(options).find(option => defaultOption?.toLowerCase() === option.toLowerCase()) || Object.keys(options)?.[0],
[options, defaultOption],
)
const handleSelect = (option?: string): void => {
toggleShow(false)
onChange?.(option)
}
useOnClickOutside(container, () => {
toggleShow(false)
})
const isDropdown = !!(options && Object.keys(options).length > 1)
return (
<Container ref={container} className={className}>
<Option
onClick={() => {
if (isDropdown) return toggleShow()
onChange?.(selected)
}}
optionName={selected}
option={options && selected ? options[selected] : undefined}
isDropdown={isDropdown}
selected
active={show}
disabled={disabled}
/>
{options && (
<OptionList hidden={!show}>
{Object.keys(options)
.filter(optionName => optionName !== selected)
.map(optionName => (
<Option
key={optionName}
onClick={() => {
handleSelect(optionName)
}}
optionName={optionName}
option={options[optionName]}
isDropdown={isDropdown}
/>
))}
</OptionList>
)}
</Container>
)
}
Example #15
Source File: index.tsx From rocketredis with MIT License | 5 votes |
ConnectionsList: React.FC = () => {
const [connections] = useRecoilState(connectionsState)
const [isCreateModalOpen, toggleCreateModalOpen] = useToggle(false)
const { t } = useTranslation('connectionList')
useEffect(() => {
ipcRenderer.addListener('newConnection', toggleCreateModalOpen)
return () => {
ipcRenderer.removeListener('newConnection', toggleCreateModalOpen)
}
}, [toggleCreateModalOpen])
return (
<>
<Container
width={300}
height={Infinity}
minConstraints={[240, Infinity]}
maxConstraints={[300, Infinity]}
className="app-sidebar"
>
<Connections>
<header>
<strong>{t('title')}</strong>
<button type="button" onClick={toggleCreateModalOpen}>
<FiPlusCircle />
</button>
</header>
<ul>
{connections.map(connection => (
<Connection key={connection.name} connection={connection} />
))}
</ul>
</Connections>
</Container>
<ConnectionFormModal
visible={isCreateModalOpen}
onRequestClose={toggleCreateModalOpen}
/>
</>
)
}
Example #16
Source File: SettingsButton.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
SettingsButton: FC<{ className?: string }> = ({ children, className }) => {
const [show, toggleShow] = useToggle(false)
const container = useRef(null)
const isDarkTheme = useIsDarkMode()
const handleThemeToggle = useToggleDarkTheme()
const showSubgraphStatus = useShowSubgraphStatus()
const handleSubgraphToggle = useToggleSubgraphStatus()
const mute = useMute()
const handleMuteToggle = useToggleMute()
useOnClickOutside(container, () => toggleShow(false))
return (
<Container ref={container} className={className}>
<Button onClick={toggleShow}>
{children || (
<div>
<SettingsSvg />
</div>
)}
</Button>
<List hidden={!show}>
<div>
<p>Network</p>
<NetworkDropdown />
</div>
<div>
<p>Theme</p>
<ThemeModeButton onClick={handleThemeToggle}>{isDarkTheme ? '?' : '☀️'}</ThemeModeButton>
</div>
<div>
<p>Sounds</p>
<ThemeModeButton onClick={handleMuteToggle}>{mute ? '?' : '?️'}</ThemeModeButton>
</div>
<div>
<Tooltip tip="Enabling this will show data fetched to support the app, and can help to resolve problems">
<p>Subgraph status</p>
</Tooltip>
<ThemeModeButton onClick={handleSubgraphToggle}>{showSubgraphStatus ? '?' : '?'}</ThemeModeButton>
</div>
</List>
</Container>
)
}
Example #17
Source File: main.tsx From platyplus with MIT License | 5 votes |
PageComponent: React.FC = () => {
const title = 'Configuration changes'
const countChanges = useCountConfigChanges()
const [show, toggle] = useToggle(false)
const saveConfig = usePersistConfig()
const save = async () => {
saveConfig()
toggle(false)
}
const reset = useResetConfig()
return (
<>
<Modal show={show} onHide={toggle}>
<Modal.Header>
<Modal.Title>{title}</Modal.Title>
</Modal.Header>
<Modal.Body>Config changes occurred: describe them here</Modal.Body>
<Modal.Footer>
<Button onClick={save} appearance="primary">
Apply
</Button>
<Button onClick={toggle} appearance="subtle">
Cancel
</Button>
</Modal.Footer>
</Modal>
<HeaderTitleWrapper title={title}>
<Animation.Fade in={true}>
{(props) => (
<div {...props}>
<ButtonToolbar>
{countChanges && (
<ButtonGroup>
<IconButtonWithHelper
icon="save"
helper="Apply changes"
onClick={toggle}
size="sm"
>
Apply changes
</IconButtonWithHelper>
<IconButtonWithHelper
icon="undo"
helper="Reset changes"
onClick={reset}
size="sm"
>
Reset
</IconButtonWithHelper>
</ButtonGroup>
)}
</ButtonToolbar>
<Panel>
<Modifications />
</Panel>
</div>
)}
</Animation.Fade>
</HeaderTitleWrapper>
</>
)
}
Example #18
Source File: StakeForm.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 4 votes |
StakeForm: FC<Props> = ({ className, isMigrating = false }) => {
const { data, loading } = useStakedTokenQuery()
const stakingQuery = useStakingQuery()
const { selected: stakedTokenAddress } = useStakedToken()
const networkAddresses = useNetworkAddresses()
const { delegateSelection: delegate } = useModalData()
const { hasWithdrawnV1Balance, lockedV1 } = useStakingStatus()
const { setWithdrewV1Balance } = useStakingStatusDispatch()
const stakingToken = useTokenSubscription(data?.stakedToken?.stakingToken.address)
const propose = usePropose()
const signer = useSigner()
const stakedTokenContract = useStakedTokenContract()
const allowance = useTokenAllowance(data?.stakedToken?.stakingToken.address, stakedTokenContract?.address)
const [amount, formValue, setFormValue] = useBigDecimalInput('0')
const [isDelegating, toggleIsDelegating] = useToggle(true)
const cooldown = parseInt(data?.stakedToken?.COOLDOWN_SECONDS) / DAY
const unstakeWindow = parseInt(data?.stakedToken?.UNSTAKE_WINDOW) / DAY
const balanceV1 = lockedV1?.value?.balance
const balanceV2 = data?.stakedToken?.accounts?.[0]?.balance?.rawBD
const canUserStake =
((isDelegating && !!delegate) || !isDelegating) && amount?.exact?.gt(0) && allowance?.exact && amount?.exact?.lte(allowance?.exact)
const otherStakedToken = useTokenSubscription(
stakedTokenAddress ? stakingQuery.data?.stakedTokens.find(st => st.id !== stakedTokenAddress)?.id : undefined,
)
const stakedInOtherToken = stakingToken?.balance?.exact.eq(0) && otherStakedToken?.balance?.exact.gt(0)
const handleWithdrawV1 = () => {
if (!signer || !data || !balanceV1?.simple) return
propose<Interfaces.IncentivisedVotingLockup, 'exit'>(
new TransactionManifest(IncentivisedVotingLockup__factory.connect(networkAddresses.vMTA, signer), 'exit', [], {
present: `Withdrawing from Staking V1`,
past: `Withdrew from Staking V1`,
}),
)
if (!hasWithdrawnV1Balance) {
setWithdrewV1Balance()
}
}
const handleDeposit = () => {
if (!stakedTokenContract || amount.exact.lte(0) || !stakingToken) return
if (delegate && isDelegating) {
if (delegate === constants.AddressZero) return
return propose<Interfaces.StakedToken, 'stake(uint256,address)'>(
new TransactionManifest(stakedTokenContract, 'stake(uint256,address)', [amount.exact, delegate], {
present: `Staking ${amount.toFixed(2)} ${stakingToken.symbol} and delegating to ${truncateAddress(delegate)}`,
past: `Staked ${amount.toFixed(2)} ${stakingToken.symbol} and delegated to ${truncateAddress(delegate)}`,
}),
)
}
propose<Interfaces.StakedToken, 'stake(uint256)'>(
new TransactionManifest(stakedTokenContract, 'stake(uint256)', [amount.exact], {
present: `Staking ${amount.toFixed(2)} ${stakingToken.symbol}`,
past: `Staked ${amount.toFixed(2)} ${stakingToken.symbol}`,
}),
)
}
return (
<Container className={className}>
<Input
isFetching={loading}
token={stakingToken}
formValue={formValue}
handleSetMax={setFormValue}
handleSetAmount={setFormValue}
spender={stakedTokenAddress}
stakedBalance={isMigrating ? balanceV1 : undefined}
isMigrating={isMigrating}
preferStaked={isMigrating}
/>
<div>
<DelegateToggle>
<h3>
Delegate voting power <Tooltip tip="Delegating your voting power will enable a vote in absence." />
</h3>
<ToggleInput onClick={toggleIsDelegating} checked={isDelegating} />
</DelegateToggle>
{isDelegating && <StyledDelegateSelection isMigrating={isMigrating} />}
</div>
{!!balanceV2?.simple && <TimeMultiplierImpact isStaking stakeDelta={amount?.exact} />}
<Warnings>
{stakedInOtherToken && (
<Warning highlight>It is generally not advisable to stake in both MTA and BPT because of increased gas costs.</Warning>
)}
<Warning>
Unstaking is subject to a cooldown period of {cooldown} days, followed by a {unstakeWindow} day withdrawable period.
</Warning>
<Warning>A redemption fee applies to all withdrawals. The longer you stake, the lower the redemption fee.</Warning>
<Warning>
In the event that the mStable protocol requires recollateralisation, you risk getting diluted{' '}
<a href="https://docs.mstable.org/using-mstable/mta-staking/staking-v2" target="_blank" rel="noopener noreferrer">
Learn More
</a>
</Warning>
</Warnings>
{isMigrating ? (
<div>
{!hasWithdrawnV1Balance && <SendButton valid={!!balanceV1?.simple} title="Withdraw from V1" handleSend={handleWithdrawV1} />}
<SendButton valid={canUserStake} title="Stake in V2" handleSend={handleDeposit} />
</div>
) : (
<SendButton valid title="Stake" handleSend={handleDeposit} />
)}
</Container>
)
}
Example #19
Source File: UserRewards.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 4 votes |
UserRewards: FC = () => {
const rewardStreams = useRewardStreams()
const isMasquerading = useIsMasquerading()
const feederVault = useSelectedFeederPoolVaultContract()
const saveVault = useSelectedSaveVaultContract()
const [selectedSaveVersion] = useSelectedSaveVersion()
const [showLockTable, toggleLockTable] = useToggle(true)
const propose = usePropose()
const contract = feederVault ?? saveVault
const showGraph = !!rewardStreams?.amounts?.total
const canClaim = !!rewardStreams?.amounts.unlocked || !!rewardStreams?.amounts.earned.unlocked
const headerTitles = ['Date unlocked', 'Amount'].map(t => ({ title: t }))
return (
<RewardsCard>
<div>
{showGraph ? (
<>
{showLockTable ? (
<GraphAndValues>
<ClaimGraph />
<RewardValues>
<RewardValue
title="Unclaimed"
label="Sent to you now"
value={rewardStreams?.amounts.earned.unlocked}
streamType={StreamType.Earned}
/>
<RewardValue
title="Unlocked"
label={(rewardStreams?.amounts.unlocked ?? 0) > 0 ? `Sent to you now` : `From previous claims`}
value={rewardStreams?.amounts.unlocked}
streamType={StreamType.Unlocked}
/>
<RewardValue
title="Locked"
label="From previous earnings"
value={(rewardStreams?.amounts.previewLocked ?? 0) + (rewardStreams?.amounts.locked ?? 0)}
streamType={StreamType.Locked}
/>
</RewardValues>
</GraphAndValues>
) : (
<CustomTable headerTitles={headerTitles}>
{rewardStreams?.lockedStreams?.map(stream => (
<TableRow key={stream.start} buttonTitle="View">
<TableCell width={75}>
{format(fromUnixTime(stream.finish), 'dd.MM.yy')}
<span> {format(fromUnixTime(stream.finish), 'HH:mm')}</span>
</TableCell>
<TableCell>
<p>{(stream.amount?.[2] ?? stream.amount?.[3])?.toFixed(2)} MTA</p>
</TableCell>
</TableRow>
))}
</CustomTable>
)}
<ClaimContainer>
<div>
<ToggleViewButton onClick={toggleLockTable}>{showLockTable ? `View Table` : `View Chart`}</ToggleViewButton>
</div>
{!isMasquerading && (
<ClaimButton
visible
valid={canClaim}
title="Claim Rewards"
handleSend={() => {
if (contract && rewardStreams) {
propose<Interfaces.BoostedVault, 'claimRewards(uint256,uint256)'>(
new TransactionManifest(contract, 'claimRewards(uint256,uint256)', rewardStreams.claimRange, {
present: 'Claiming rewards',
past: 'Claimed rewards',
}),
)
}
}}
/>
)}
</ClaimContainer>
</>
) : (
<EmptyState>
<h3>No rewards to claim</h3>
{selectedSaveVersion === 1 ? (
<p>Migrate your balance and deposit to the Vault to earn MTA rewards.</p>
) : (
<p>Deposit to the Vault to earn MTA rewards.</p>
)}
</EmptyState>
)}
</div>
</RewardsCard>
)
}
Example #20
Source File: ClaimButtons.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 4 votes |
ClaimButtons: FC<{ questId: string }> = ({ questId }) => {
const account = useAccount()
const clients = useApolloClients()
const addQuestNotification = useAddQuestNotification()
const [isPending, toggleIsPending] = useToggle(false)
const questManagerContract = useQuestManagerContract()
const propose = usePropose()
const [playBleep28] = useSound(bleep28, { volume: 0.2 })
const [playBleep29] = useSound(bleep29, { volume: 0.2 })
const [updateQuest] = useUpdateQuestMutation({
client: clients.questbook,
variables: { questId, userId: account, hasUser: !!account },
onCompleted: data => {
const { userQuest, title, objectives } = data.updateQuest
if (userQuest) return
const nowUnix = getUnixTime(Date.now())
if (userQuest.completedAt && nowUnix - userQuest.completedAt < 30) {
addQuestNotification(title)
}
userQuest.objectives
.filter(obj => obj.completedAt && nowUnix - obj.completedAt < 30)
.forEach(obj => {
const obj_ = objectives.find(_obj => _obj.id === obj.id)
if (obj_) addQuestNotification(obj_.title, obj_.points)
})
},
})
const questbookQuery = useQuestbookQuestQuery({
client: clients.questbook,
variables: { questId, userId: account ?? '', hasUser: !!account },
pollInterval: 15e3,
})
const questbookQuest = questbookQuery.data?.quest
const ethereumId = questbookQuest?.ethereumId?.toString()
const questQuery = useQuestQuery({
client: clients.staking,
variables: { id: ethereumId as string },
skip: !ethereumId,
})
const accountQuery = useAccountQuery({
client: clients.staking,
variables: { id: account ?? '' },
skip: !account,
pollInterval: 15e3,
nextFetchPolicy: 'cache-only',
})
const claimed = accountQuery.data?.account?.completedQuests?.find(c => c.quest.id === questbookQuest?.ethereumId?.toString())
const readyToClaim = !claimed && questbookQuest?.userQuest?.complete
const questExpired = questQuery.data?.quest && questQuery.data.quest.expiry < nowUnix
const handleClaimQuest = () => {
if (
isPending ||
!questManagerContract ||
!questbookQuest ||
typeof questbookQuest.ethereumId !== 'number' ||
!questbookQuest.userQuest?.signature
)
return
propose(
new TransactionManifest<Interfaces.QuestManager, 'completeUserQuests'>(
questManagerContract,
'completeUserQuests',
[account, [questbookQuest.ethereumId], questbookQuest.userQuest.signature],
{
present: 'Complete quest',
past: 'Completed quest',
},
),
)
}
const handleRefresh = () => {
if (isPending) return
playBleep28()
toggleIsPending(true)
updateQuest()
.catch(error => {
console.error(error)
})
.finally(() => {
toggleIsPending(false)
playBleep29()
})
}
return claimed ? (
<Button disabled>Claimed</Button>
) : readyToClaim ? (
<Button highlighted onClick={handleClaimQuest} disabled={isPending || questExpired || !ethereumId}>
{ethereumId ? (
questExpired ? (
'Expired'
) : (
'Claim'
)
) : (
<Tooltip tip="This quest is not available to complete on-chain yet, but it will be in the near future">Claim</Tooltip>
)}
</Button>
) : (
<Button highlighted onClick={handleRefresh} disabled={isPending}>
{isPending ? 'Checking...' : 'Check status'}
</Button>
)
}
Example #21
Source File: index.tsx From rocketredis with MIT License | 4 votes |
DeleteConnectionModal: React.FC<ConnectionModalProps> = ({
visible,
onRequestClose,
connectionToDelete
}) => {
const formRef = useRef<FormHandles>(null)
const { t } = useTranslation('deleteConnection')
const { addToast } = useToast()
const setConnections = useSetRecoilState(connectionsState)
const [deleteConnectionLoading, toggleDeleteConnectionLoading] = useToggle(
false
)
const handleCloseModal = useCallback(() => {
if (onRequestClose) {
onRequestClose()
}
}, [onRequestClose])
const handleDeleteConnection = useCallback(
async ({ confirmation: deleteConfirmation }: DeleteConnectionFormData) => {
try {
toggleDeleteConnectionLoading()
formRef.current?.setErrors({})
if (deleteConfirmation !== 'DELETE') {
formRef.current?.setErrors({
confirmation: t('form.unconfirmedDeletionError')
})
return
}
const connections = deleteAndGetConnections(connectionToDelete)
setConnections(connections)
addToast({
type: 'success',
title: 'Connection deleted',
description: 'This connection will not be available anymore.'
})
handleCloseModal()
} catch (error) {
addToast({
type: 'error',
title: 'Error deleting connection',
description: error.message || 'Unexpected error occurred, try again.'
})
} finally {
toggleDeleteConnectionLoading()
}
},
[
toggleDeleteConnectionLoading,
t,
addToast,
connectionToDelete,
setConnections,
handleCloseModal
]
)
return (
<Modal visible={visible} onRequestClose={onRequestClose}>
<h1>{t('title')}</h1>
<TextContent>
<p>
<Trans
t={t}
i18nKey="deletingConnectionMessage"
values={{ name: connectionToDelete.name }}
>
The connection <strong>{name}</strong> will be permanently deleted.
</Trans>
</p>
<p>
<Trans t={t} i18nKey="confirmDeletionMessage" />
</p>
</TextContent>
<Form ref={formRef} onSubmit={handleDeleteConnection}>
<Input name="confirmation" />
<ActionsContainer>
<ButtonGroup>
<Button onClick={handleCloseModal} type="button" color="opaque">
{t('form.cancel')}
</Button>
<Button loading={deleteConnectionLoading} type="submit" color="red">
<FiTrash />
{t('form.confirmDeletion')}
</Button>
</ButtonGroup>
</ActionsContainer>
</Form>
</Modal>
)
}
Example #22
Source File: index.tsx From rocketredis with MIT License | 4 votes |
ConnectionFormModal: React.FC<ConnectionModalProps> = ({
visible,
onRequestClose,
connectionToEdit
}) => {
const formRef = useRef<FormHandles>(null)
const { addToast } = useToast()
const setConnections = useSetRecoilState(connectionsState)
const { t } = useTranslation('connectionForm')
const [testConnectionLoading, toggleTestConnectionLoading] = useToggle(false)
const [createConnectionLoading, toggleCreateConnectionLoading] = useToggle(
false
)
const handleCloseModal = useCallback(() => {
if (onRequestClose) {
onRequestClose()
}
}, [onRequestClose])
const handleCreateOrUpdateConnection = useCallback(
async (data: ConnectionFormData) => {
try {
formRef.current?.setErrors({})
const schema = Yup.object().shape({
name: Yup.string().required(),
host: Yup.string().required(),
port: Yup.number().required(),
password: Yup.string()
})
toggleCreateConnectionLoading()
await schema.validate(data, {
abortEarly: false
})
const { name, host, port, password } = data
try {
const connectionData = {
name,
host,
port: Number(port),
password
}
const connections = connectionToEdit
? updateAndGetConnections(connectionToEdit, connectionData)
: createAndGetConnections(connectionData)
setConnections(connections)
addToast({
type: 'success',
title: 'Connection saved',
description: 'You can now connect to your database!'
})
handleCloseModal()
} catch (err) {
addToast({
type: 'error',
title: 'Error saving connection',
description: err.message || 'Unexpected error occurred, try again.'
})
}
} catch (err) {
if (err instanceof Yup.ValidationError) {
const errors = getValidationErrors(err)
formRef.current?.setErrors(errors)
}
} finally {
toggleCreateConnectionLoading()
}
},
[
addToast,
setConnections,
toggleCreateConnectionLoading,
connectionToEdit,
handleCloseModal
]
)
const handleTestConnection = useCallback(async () => {
if (!formRef.current) {
return
}
const {
host,
port,
password
} = formRef.current.getData() as ConnectionFormData
try {
formRef.current?.setErrors({})
toggleTestConnectionLoading()
const schema = Yup.object().shape({
host: Yup.string().required(),
port: Yup.number().required(),
password: Yup.string()
})
const data = {
host,
port
}
await schema.validate(data, {
abortEarly: false
})
await testConnection({
host,
port: Number(port),
password
})
addToast({
type: 'success',
title: 'Connection successful',
description: 'Urrray... You can save your connection now!'
})
} catch (err) {
if (err instanceof Yup.ValidationError) {
const errors = getValidationErrors(err)
formRef.current?.setErrors(errors)
} else {
addToast({
type: 'error',
title: 'Error on connection',
description: 'Error estabilishing connection with your Redis server'
})
}
} finally {
toggleTestConnectionLoading()
}
}, [addToast, toggleTestConnectionLoading])
return (
<Modal visible={visible} onRequestClose={onRequestClose}>
<h1>
{connectionToEdit ? t('editConnectionTitle') : t('newConnectionTitle')}
</h1>
<Form
initialData={{
name: connectionToEdit?.name,
host: connectionToEdit?.host || 'localhost',
port: connectionToEdit?.port || '6379'
}}
ref={formRef}
onSubmit={handleCreateOrUpdateConnection}
>
<Input name="name" label={t('form.name')} />
<InputGroup>
<Input name="host" label={t('form.host')} />
<Input name="port" label={t('form.port')} />
</InputGroup>
<Input
type="password"
name="password"
label={t('form.password')}
hint={t('form.passwordHint')}
/>
<ActionsContainer>
<TestConnectionButton
loading={testConnectionLoading}
color="pink"
onClick={handleTestConnection}
>
<FiActivity />
{t('form.test')}
</TestConnectionButton>
<ButtonGroup>
<Button onClick={handleCloseModal} type="button" color="opaque">
{t('form.cancel')}
</Button>
<Button
loading={createConnectionLoading}
type="submit"
color="purple"
>
<FiSave />
{t('form.save')}
</Button>
</ButtonGroup>
</ActionsContainer>
</Form>
</Modal>
)
}
Example #23
Source File: inline-value.tsx From platyplus with MIT License | 4 votes |
InlineValue: React.FC<{
editable?: boolean
value: string
label?: string
onChange: (value: string) => void
}> = ({ editable = true, value, label, onChange }) => {
// * Toggle title editing
const [editing, toggle] = useToggle(false)
const readValue = useMemo(() => label ?? value, [value, label])
// * Input value state
const [inputValue, setInputValue] = useState('')
useEffect(() => {
setInputValue(value)
}, [value])
// * Cancel title editing
const cancel = () => {
toggle(false)
setInputValue(value)
}
// * Set title into the config store
const validate = () => {
toggle(false)
onChange(inputValue)
}
// * If editing and clicking away, stop editing
const ref = useRef(null)
useClickAway(ref, cancel)
// * Adjust Input width automatically
// TODO width does not scale correctly with value length
// * See useSize in react-use
const [width, setWidth] = useState(`${14 + value?.length}ch`)
useEffect(() => setWidth(`${14 + inputValue?.length}ch`), [inputValue])
return (
<Animation.Fade in={!!value}>
{(props) => (
<span {...props}>
{editing ? (
<div
ref={ref}
style={{
width,
display: 'inline-block'
}}
>
<InputGroup size="xs">
<Input
size="xs"
value={inputValue}
onChange={setInputValue}
onKeyDown={({ key }) => key === 'Enter' && validate()}
autoFocus
/>
<InputGroup.Button size="xs" onClick={cancel}>
<Icon icon="close" />
</InputGroup.Button>
<InputGroup.Button size="xs" onClick={validate}>
<Icon icon="check" />
</InputGroup.Button>
</InputGroup>
</div>
) : editable ? (
<span onClick={toggle}>
{readValue ? (
readValue
) : (
<IconButton size="xs" icon={<Icon icon="edit" />}>
Edit template
</IconButton>
)}
</span>
) : (
<span>{readValue}</span>
)}
</span>
)}
</Animation.Fade>
)
}
Example #24
Source File: index.tsx From rocketredis with MIT License | 4 votes |
Connection: React.FC<IConnectionProps> = ({ connection }) => {
const [currentConnection, setCurrentConnection] = useRecoilState(
currentConnectionState
)
const [currentDatabase, setCurrentDatabase] = useRecoilState(
currentDatabaseState
)
const setCurrentKey = useSetRecoilState(currentKeyState)
const [databases, setDatabases] = useState<IDatabase[]>([])
const [connectionLoading, setConnectionLoading] = useState(false)
const [isConnectionFailed, setIsConnectionFailed] = useState(false)
const [isEditModalOpen, toggleEditModalOpen] = useToggle(false)
const [isDeleteModalOpen, toggleDeleteModalOpen] = useToggle(false)
const { t } = useTranslation('connection')
const { addToast } = useToast()
useEffect(() => {
if (currentConnection) {
setIsConnectionFailed(false)
}
}, [currentConnection])
const isConnected = useMemo(() => {
return currentConnection?.name === connection.name
}, [currentConnection?.name, connection.name])
const handleConnect = useCallback(async () => {
if (!isConnected) {
setConnectionLoading(true)
setCurrentConnection(undefined)
setCurrentDatabase(undefined)
setCurrentKey(undefined)
try {
const databases = await loadConnectionDatabases(connection)
setDatabases(databases)
setCurrentConnection(connection)
setCurrentDatabase(undefined)
} catch {
setIsConnectionFailed(true)
} finally {
setConnectionLoading(false)
}
}
}, [
connection,
isConnected,
setCurrentConnection,
setCurrentDatabase,
setCurrentKey
])
const handleDisconnect = useCallback(async () => {
setCurrentConnection(undefined)
setCurrentDatabase(undefined)
terminateConnection()
}, [setCurrentConnection, setCurrentDatabase])
const handleRefreshDatabases = useCallback(async () => {
try {
setConnectionLoading(true)
const databases = await loadConnectionDatabases(connection)
setDatabases(databases)
} catch {
setIsConnectionFailed(true)
} finally {
setConnectionLoading(false)
}
}, [connection])
const postSavingConnection = useCallback(async () => {
toggleEditModalOpen()
setCurrentConnection(undefined)
setCurrentDatabase(undefined)
setIsConnectionFailed(false)
}, [toggleEditModalOpen, setCurrentConnection, setCurrentDatabase])
const postDeletingConnection = useCallback(async () => {
toggleDeleteModalOpen()
setCurrentConnection(undefined)
setCurrentDatabase(undefined)
terminateConnection()
}, [toggleDeleteModalOpen, setCurrentConnection, setCurrentDatabase])
const handleSelectDatabase = useCallback(
async (database: IDatabase) => {
if (!currentConnection) {
return
}
try {
await initializeConnection(currentConnection, database)
setCurrentDatabase(database)
setCurrentKey(undefined)
} catch {
addToast({
type: 'error',
title: 'Failed to connect to database',
description:
'A connection to this Redis database could not be established.'
})
}
},
[currentConnection, addToast, setCurrentDatabase, setCurrentKey]
)
return (
<>
<Container
key={connection.name}
connected={isConnected}
errored={isConnectionFailed}
>
<ContextMenuTrigger id={`connection_actions_menu:${connection.name}`}>
<button type="button" disabled={isConnected} onClick={handleConnect}>
{connectionLoading ? (
<Loading>
<FiLoader />
</Loading>
) : (
<FiDatabase />
)}
{connection.name}
<FiChevronRight />
</button>
</ContextMenuTrigger>
<ContextMenu
id={`connection_actions_menu:${connection.name}`}
className="connection-actions-menu"
>
{isConnected ? (
<MenuItem onClick={handleDisconnect}>
<DisconnectButton>
<FiMinusCircle />
{t('contextMenu.disconnect')}
</DisconnectButton>
</MenuItem>
) : (
<MenuItem onClick={handleConnect}>
<ConnectButton>
<FiActivity />
{t('contextMenu.connect')}
</ConnectButton>
</MenuItem>
)}
<MenuItem onClick={toggleEditModalOpen}>
<FiEdit2 />
{t('contextMenu.editSettings')}
</MenuItem>
{isConnected && (
<MenuItem onClick={handleRefreshDatabases}>
<FiRefreshCcw />
{t('contextMenu.refreshDatabases')}
</MenuItem>
)}
<MenuItem onClick={toggleDeleteModalOpen}>
<FiTrash />
{t('contextMenu.deleteConnection')}
</MenuItem>
</ContextMenu>
{isConnected && !!databases.length && (
<DatabaseList>
{databases.map(database => (
<Database
connected={currentDatabase?.name === database.name}
key={database.name}
onClick={() => handleSelectDatabase(database)}
type="button"
>
<strong>{database.name}</strong>
<span>
{database.keys} {t('keys')}
</span>
</Database>
))}
</DatabaseList>
)}
{isConnectionFailed && (
<ConnectionError>
{t('connectionFailed')}{' '}
<button type="button" onClick={handleConnect}>
{t('retry')}
</button>
</ConnectionError>
)}
</Container>
<ConnectionFormModal
visible={isEditModalOpen}
onRequestClose={postSavingConnection}
connectionToEdit={connection}
/>
<DeleteConnectionModal
visible={isDeleteModalOpen}
onRequestClose={postDeletingConnection}
connectionToDelete={connection}
/>
</>
)
}