diff --git a/packages/ui/src/common/components/forms/FilterBox/FilterSearchBox.tsx b/packages/ui/src/common/components/forms/FilterBox/FilterSearchBox.tsx
index a9b20766ea..8191fa5bd0 100644
--- a/packages/ui/src/common/components/forms/FilterBox/FilterSearchBox.tsx
+++ b/packages/ui/src/common/components/forms/FilterBox/FilterSearchBox.tsx
@@ -41,9 +41,16 @@ interface SearchBoxProps extends ControlProps {
}
export const SearchBox = React.memo(({ value, onApply, onChange, label, displayReset }: SearchBoxProps) => {
const change = onChange && (({ target }: ChangeEvent) => onChange(target.value))
- const isValid = () => !value || value.length === 0 || value.length > 2
- const keyDown =
- !isValid() || !value || !onApply ? undefined : ({ key }: React.KeyboardEvent) => key === 'Enter' && onApply()
+ const isValid = !value || value.length === 0 || value.length > 2
+ const [showInvalid, setShowInvalid] = useState(false)
+ useEffect(() => {
+ if (isValid) setShowInvalid(false)
+ }, [isValid])
+ const keyDown = ({ key }: React.KeyboardEvent) => {
+ if (key !== 'Enter') return
+ if (!isValid) return setShowInvalid(true)
+ onApply?.()
+ }
const reset =
onChange &&
onApply &&
@@ -56,8 +63,8 @@ export const SearchBox = React.memo(({ value, onApply, onChange, label, displayR
{label}
{displayReset && value && (
diff --git a/packages/ui/src/common/utils/object.ts b/packages/ui/src/common/utils/object.ts
index 65b3fce5d8..4e9f1a086b 100644
--- a/packages/ui/src/common/utils/object.ts
+++ b/packages/ui/src/common/utils/object.ts
@@ -22,3 +22,6 @@ const mapEntries = (
transform: (x: any, key?: string | number, context?: AnyObject) => any,
context?: AnyObject
): [any, any][] => entries.map(([key, value]) => [key, transform(value, key, context)])
+
+export const has = >(key: K, o: T): key is Extract =>
+ key in o
diff --git a/packages/ui/src/memberships/components/MemberProfile/MemberDetails.tsx b/packages/ui/src/memberships/components/MemberProfile/MemberDetails.tsx
index 57030ff329..73691375de 100644
--- a/packages/ui/src/memberships/components/MemberProfile/MemberDetails.tsx
+++ b/packages/ui/src/memberships/components/MemberProfile/MemberDetails.tsx
@@ -13,6 +13,8 @@ import {
SidePaneLabel,
EmptyBody,
} from '@/common/components/SidePane'
+import { has } from '@/common/utils/object'
+import { ExternalResourceLink } from '@/memberships/constants'
import { useIsMyMembership } from '@/memberships/hooks/useIsMyMembership'
import { useMemberExtraInfo } from '@/memberships/hooks/useMemberExtraInfo'
@@ -37,15 +39,6 @@ export const MemberDetails = React.memo(({ member }: Props) => {
initiatingLeaving = '-',
} = useMemberExtraInfo(member)
- const externalResourceLink: any = {
- TELEGRAM: 'https://web.telegram.org/k/#@',
- TWITTER: 'https://twitter.com/',
- FACEBOOK: 'https://facebook.com/',
- YOUTUBE: 'https://youtube.com/user/',
- LINKEDIN: 'https://www.linkedin.com/in/',
- GITHUB: 'https://github.com/',
- }
-
if (isLoading || !memberDetails) {
return (
@@ -143,9 +136,9 @@ export const MemberDetails = React.memo(({ member }: Props) => {
- {externalResourceLink[externalResource.source] ? (
+ {has(externalResource.source, ExternalResourceLink) ? (
{externalResource.value}
diff --git a/packages/ui/src/memberships/constants/externalResourceLink.ts b/packages/ui/src/memberships/constants/externalResourceLink.ts
new file mode 100644
index 0000000000..ac2740193c
--- /dev/null
+++ b/packages/ui/src/memberships/constants/externalResourceLink.ts
@@ -0,0 +1,8 @@
+export const ExternalResourceLink = {
+ TELEGRAM: 'https://t.me/',
+ TWITTER: 'https://twitter.com/',
+ FACEBOOK: 'https://facebook.com/',
+ YOUTUBE: 'https://youtube.com/user/',
+ LINKEDIN: 'https://www.linkedin.com/in/',
+ GITHUB: 'https://github.com/',
+} as const
diff --git a/packages/ui/src/memberships/constants/index.ts b/packages/ui/src/memberships/constants/index.ts
index 856f210744..d21e69ee07 100644
--- a/packages/ui/src/memberships/constants/index.ts
+++ b/packages/ui/src/memberships/constants/index.ts
@@ -1 +1,2 @@
export * from './email'
+export * from './externalResourceLink'
diff --git a/packages/ui/src/validators/components/ValidatorInfo.tsx b/packages/ui/src/validators/components/ValidatorInfo.tsx
index 7a419e19b6..2a97a731dc 100644
--- a/packages/ui/src/validators/components/ValidatorInfo.tsx
+++ b/packages/ui/src/validators/components/ValidatorInfo.tsx
@@ -4,12 +4,14 @@ import styled from 'styled-components'
import { CopyComponent } from '@/common/components/CopyComponent'
import { DiscordIcon, TelegramIcon, TwitterIcon } from '@/common/components/icons/socials'
+import { Link } from '@/common/components/Link'
import { DefaultTooltip, Tooltip } from '@/common/components/Tooltip'
import { BorderRad, Colors, Transitions } from '@/common/constants'
import { shortenAddress } from '@/common/model/formatters'
import { Address } from '@/common/types'
import { MemberIcons } from '@/memberships/components'
import { Avatar } from '@/memberships/components/Avatar'
+import { ExternalResourceLink } from '@/memberships/constants'
import { MemberWithDetails } from '@/memberships/types'
interface ValidatorInfoProps {
@@ -39,18 +41,18 @@ export const ValidatorInfo = React.memo(({ address, member, size = 's' }: Valida
{(twitter || telegram || discord) && (
{twitter && (
-
+ e.stopPropagation()} href={`${ExternalResourceLink.TWITTER}${twitter.value}`}>
-
+
)}
{telegram && (
-
+ e.stopPropagation()} href={`${ExternalResourceLink.TELEGRAM}${telegram.value}`}>
-
+
)}
{discord && (
diff --git a/packages/ui/src/validators/components/ValidatorsFilter.tsx b/packages/ui/src/validators/components/ValidatorsFilter.tsx
index 5772a80b38..7b046d63ec 100644
--- a/packages/ui/src/validators/components/ValidatorsFilter.tsx
+++ b/packages/ui/src/validators/components/ValidatorsFilter.tsx
@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
-import { FilterBox } from '@/common/components/forms/FilterBox'
+import { InputNotification } from '@/common/components/forms'
+import { Fields, FilterBox } from '@/common/components/forms/FilterBox'
import { SearchBox } from '@/common/components/forms/FilterBox/FilterSearchBox'
import { FilterSelect } from '@/common/components/selects'
@@ -24,8 +25,8 @@ export const ValidatorsFilter = ({ filter }: ValidatorFilterProps) => {
const display = () => filter.setSearch(search)
const { isVerified, isActive } = filter
- const verificationValue = isVerified === true ? 'verified' : isVerified === false ? 'unverified' : undefined
- const stateValue = isActive === true ? 'active' : isActive === false ? 'waiting' : undefined
+ const verificationValue = isVerified === true ? 'verified' : isVerified === false ? 'unverified' : null
+ const stateValue = isActive === true ? 'active' : isActive === false ? 'waiting' : null
const clear =
filter.search || verificationValue || stateValue
@@ -37,8 +38,8 @@ export const ValidatorsFilter = ({ filter }: ValidatorFilterProps) => {
: undefined
return (
-
-
+
+
{
/>
-
-
+
+
)
}
+const ValidatorFilterBox = styled(FilterBox)`
+ ${Fields} {
+ padding-bottom: 22px;
+ }
+`
+
const SelectFields = styled.div`
display: flex;
justify-content: flex-start;
@@ -74,11 +81,16 @@ const SelectFields = styled.div`
}
}
`
-const Fields = styled.div`
+const ResponsiveWrapper = styled.div`
display: flex;
justify-content: space-between;
gap: 8px;
+ ${InputNotification} {
+ top: unset;
+ bottom: 2px;
+ }
+
@media (max-width: 767px) {
flex-direction: column;
}
diff --git a/packages/ui/src/validators/components/ValidatorsList.tsx b/packages/ui/src/validators/components/ValidatorsList.tsx
index 0f9ef40cda..a45eeaa3b4 100644
--- a/packages/ui/src/validators/components/ValidatorsList.tsx
+++ b/packages/ui/src/validators/components/ValidatorsList.tsx
@@ -65,7 +65,7 @@ export const ValidatorsList = ({ validators, eraIndex, order, pagination }: Vali
The APR is subject to the amount staked and have a diminishing return for higher token amounts. This
is calculated as follow:
- Yearly Reward * Commission / Stake
+ Yearly Reward * (1 - Commission) / Stake
- Reward:
- Average reward generated (during the last 30 days) extrapolated over a year.
@@ -88,6 +88,9 @@ export const ValidatorsList = ({ validators, eraIndex, order, pagination }: Vali
isDescending={order.isDescending}
>
Commission
+ The validator commission on the nominators rewards
}>
+
+
{!validators ? (
diff --git a/packages/ui/src/validators/components/statistics/Era.tsx b/packages/ui/src/validators/components/statistics/Era.tsx
index 4babce7c28..10f52d7304 100644
--- a/packages/ui/src/validators/components/statistics/Era.tsx
+++ b/packages/ui/src/validators/components/statistics/Era.tsx
@@ -12,7 +12,7 @@ import {
import { DurationValue } from '@/common/components/typography/DurationValue'
import { ERA_DURATION } from '@/common/constants'
import { MILLISECONDS_PER_BLOCK } from '@/common/model/formatters'
-import { whenDefined } from '@/common/utils'
+import { isDefined, whenDefined } from '@/common/utils'
interface EraProps {
eraStartedOn: number | undefined
@@ -44,23 +44,23 @@ export const Era = ({ eraStartedOn }: EraProps) => {
tooltipText="One era consists of 6 epochs with 1 hour duration each."
tooltipTitle="Era"
tooltipLinkText="What is an era"
- actionElement={}
+ actionElement={isDefined(percentage) && }
>
Next Reward
-
-
-
+ {isDefined(nextReward) && }
Blocks / Points
-
- {blocks && (
-
+
+ {blocks ? (
+ <>
{blocks} / {blocks * POINTS_PER_BLOCK}
-
+ >
+ ) : (
+ '- / -'
)}
-
+
)
diff --git a/packages/ui/src/validators/components/statistics/Rewards.tsx b/packages/ui/src/validators/components/statistics/Rewards.tsx
index 7e66d5b6dc..94d0d97c5b 100644
--- a/packages/ui/src/validators/components/statistics/Rewards.tsx
+++ b/packages/ui/src/validators/components/statistics/Rewards.tsx
@@ -23,7 +23,7 @@ export const Rewards = ({ totalRewards, lastRewards }: RewardsProps) => {
- Last
+ Last Era
diff --git a/packages/ui/src/validators/components/statistics/Staking.tsx b/packages/ui/src/validators/components/statistics/Staking.tsx
index 319a042c3b..204771cac8 100644
--- a/packages/ui/src/validators/components/statistics/Staking.tsx
+++ b/packages/ui/src/validators/components/statistics/Staking.tsx
@@ -20,10 +20,10 @@ export const Staking = ({ idealStaking, currentStaking, stakingPercentage }: Sta
return (
diff --git a/packages/ui/src/validators/components/statistics/ValidatorsState.tsx b/packages/ui/src/validators/components/statistics/ValidatorsState.tsx
index f35be07583..2abc3e5d90 100644
--- a/packages/ui/src/validators/components/statistics/ValidatorsState.tsx
+++ b/packages/ui/src/validators/components/statistics/ValidatorsState.tsx
@@ -16,23 +16,21 @@ export const ValidatorsState = ({
allNominatorsCount,
}: ValidatorsStateProps) => {
return (
-
+
Validator (Active / Waiting)
- {activeValidatorsCount} / {allValidatorsCount - activeValidatorsCount}
+ {`${activeValidatorsCount > 0 ? activeValidatorsCount : '-'} / ${
+ allValidatorsCount && activeValidatorsCount ? allValidatorsCount - activeValidatorsCount : '-'
+ }`}
Nominator (Active / Total)
- {activeNominatorsCount} / {allNominatorsCount}
+ {`${activeNominatorsCount > 0 ? activeValidatorsCount : '-'} / ${
+ activeNominatorsCount && allNominatorsCount ? allNominatorsCount : '-'
+ }`}
diff --git a/packages/ui/src/validators/hooks/useValidatorsList.tsx b/packages/ui/src/validators/hooks/useValidatorsList.tsx
index d5d23f79eb..8a5ae7b717 100644
--- a/packages/ui/src/validators/hooks/useValidatorsList.tsx
+++ b/packages/ui/src/validators/hooks/useValidatorsList.tsx
@@ -4,7 +4,7 @@ import { ValidatorsContext } from '../providers/context'
import { ValidatorDetailsOrder } from '../types'
const VALIDATOR_PER_PAGE = 7
-const DESCENDING_KEYS: ValidatorDetailsOrder['key'][] = ['apr', 'commission']
+const DESCENDING_KEYS: ValidatorDetailsOrder['key'][] = ['apr']
export const useValidatorsList = () => {
const [search, setSearch] = useState('')
diff --git a/packages/ui/src/validators/modals/NominatingRedirectModal/NominatingRedirectModal.tsx b/packages/ui/src/validators/modals/NominatingRedirectModal/NominatingRedirectModal.tsx
index dd058515e7..e5c13617bc 100644
--- a/packages/ui/src/validators/modals/NominatingRedirectModal/NominatingRedirectModal.tsx
+++ b/packages/ui/src/validators/modals/NominatingRedirectModal/NominatingRedirectModal.tsx
@@ -29,7 +29,7 @@ export const NominatingRedirectModal = () => {
size="medium"
href="https://polkadot.js.org/apps/?rpc=wss://rpc.joystream.org:9944#/staking/actions"
>
- Norminate
+ Nominate
diff --git a/packages/ui/src/validators/modals/validatorCard/Nominators.tsx b/packages/ui/src/validators/modals/validatorCard/Nominators.tsx
index d7c9df0f6d..acaa3689fe 100644
--- a/packages/ui/src/validators/modals/validatorCard/Nominators.tsx
+++ b/packages/ui/src/validators/modals/validatorCard/Nominators.tsx
@@ -29,10 +29,10 @@ export const Nominators = ({ validator }: Props) => {
{validator.staking?.nominators?.map(({ address, staking }, index) => (
-
+
-
+
))}
@@ -51,10 +51,9 @@ const Title = styled.h4`
const NominatorList = styled(List)`
gap: 8px;
`
-const ValidatorItemWrap = styled.div`
+const NominatorItemWrap = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr;
justify-content: space-between;
justify-items: end;
align-items: center;
@@ -65,6 +64,11 @@ const ValidatorItemWrap = styled.div`
cursor: pointer;
transition: ${Transitions.all};
${TableListItemAsLinkHover}
+
+ @media (max-width: 424px) {
+ grid-gap: 8px;
+ grid-template-columns: 1fr;
+ }
`
const ListHeaders = styled.div`
display: grid;
diff --git a/packages/ui/src/validators/modals/validatorCard/ValidatorDetail.tsx b/packages/ui/src/validators/modals/validatorCard/ValidatorDetail.tsx
index 15fbb8bba6..e46b788ce1 100644
--- a/packages/ui/src/validators/modals/validatorCard/ValidatorDetail.tsx
+++ b/packages/ui/src/validators/modals/validatorCard/ValidatorDetail.tsx
@@ -68,7 +68,9 @@ export const ValidatorDetail = ({ validator, eraIndex, hideModal }: Props) => {
Era points
-
+
+
+
)}
@@ -115,6 +117,14 @@ const Details = styled(RowGapBlock)`
const ModalStatistics = styled(StatisticsThreeColumns)`
grid-gap: 10px;
+
+ @media (max-width: 767px) {
+ grid-template-columns: 1fr 1fr;
+ }
+
+ @media (max-width: 424px) {
+ grid-template-columns: 1fr;
+ }
`
const Stat = styled(NumericValueStat)`
@@ -123,5 +133,10 @@ const Stat = styled(NumericValueStat)`
const RewardPointsChartWrapper = styled.div`
width: 100%;
- height: 200px;
+ overflow: auto;
+
+ > div {
+ min-width: 500px;
+ height: 200px;
+ }
`
diff --git a/packages/ui/src/validators/providers/utils.ts b/packages/ui/src/validators/providers/utils.ts
index 59cb67132a..00c4349b5f 100644
--- a/packages/ui/src/validators/providers/utils.ts
+++ b/packages/ui/src/validators/providers/utils.ts
@@ -130,7 +130,14 @@ export const getValidatorInfo = (
const commission = validator.commission
const averageReward = rewards.reduce((sum, reward) => sum.add(reward.eraReward), BN_ZERO).divn(rewards.length)
- const apr = Number(averageReward.muln(ERAS_PER_YEAR).muln(commission).div(staking.total))
+ const apr =
+ Number(
+ averageReward
+ .muln(ERAS_PER_YEAR)
+ .muln(100 - commission)
+ .muln(100)
+ .div(staking.total)
+ ) / 100
return { APR: apr }
})
)