diff --git a/src/api/auth/getConfig.ts b/src/api/auth/getConfig.ts index 80e07a62b..b109c5d2b 100644 --- a/src/api/auth/getConfig.ts +++ b/src/api/auth/getConfig.ts @@ -1,12 +1,17 @@ // SPDX-License-Identifier: ice License 1.0 -import {AuthConfig} from '@api/auth/types'; +import {FeatureToggleConfig} from '@api/auth/types'; import {get} from '@api/client'; import {NO_CACHE_HEADERS} from '@api/client/getHeaders'; import {ENV} from '@constants/env'; export function getConfig() { - return get(ENV.AUTH_CONFIG_URL ?? '', undefined, undefined, { - headers: NO_CACHE_HEADERS, - }); + return get( + ENV.AUTH_CONFIG_URL ?? '', + undefined, + undefined, + { + headers: NO_CACHE_HEADERS, + }, + ); } diff --git a/src/api/auth/types.ts b/src/api/auth/types.ts index 7a959d08b..68b581f99 100644 --- a/src/api/auth/types.ts +++ b/src/api/auth/types.ts @@ -27,7 +27,7 @@ type EthDistributionKyc = { }; }; -export type AuthConfig = AuthCodeConfig & +export type FeatureToggleConfig = AuthCodeConfig & FaceAuthConfig & TeamConfig & AchievementsConfig & diff --git a/src/api/statistics/types.ts b/src/api/statistics/types.ts index e114e0de8..5689a6651 100644 --- a/src/api/statistics/types.ts +++ b/src/api/statistics/types.ts @@ -15,10 +15,10 @@ export type Miner = { export type UserGrowth = { active: number; // 0, total: number; // 20 - timeSeries: TimeSeries[]; + timeSeries: UserGrowthTimeSeries[]; }; -export type TimeSeries = { +export type UserGrowthTimeSeries = { date: string; // "2022-11-30T16:35:02.996090946Z", active: number; // 0, total: number; // 20 @@ -36,3 +36,9 @@ export type Adoption = { milestones: AdoptionMilestone[]; totalActiveUsers: number; }; + +export type TotalCoinsFilter = + | 'total' + | 'on-app' + | 'pre-staked' + | 'on-blockchain'; diff --git a/src/api/tokenomics/getTotalCoins.ts b/src/api/tokenomics/getTotalCoins.ts new file mode 100644 index 000000000..a7aa4a7a2 --- /dev/null +++ b/src/api/tokenomics/getTotalCoins.ts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {get} from '@api/client'; +import {TotalCoins} from '@api/tokenomics/types'; + +type Params = { + days: number; + tz: string; +}; + +export function getTotalCoins({days, tz}: Params) { + return get('/tokenomics-statistics/total-coins', { + days, + tz, + }); +} diff --git a/src/api/tokenomics/index.ts b/src/api/tokenomics/index.ts index 7c09bd0f7..c2ff6f2e3 100644 --- a/src/api/tokenomics/index.ts +++ b/src/api/tokenomics/index.ts @@ -6,6 +6,7 @@ import {getBalanceSummary} from './getBalanceSummary'; import {getMiningSummary} from './getMiningSummary'; import {getPreStakingSummary} from './getPreStakingSummary'; import {getRankingSummary} from './getRankingSummary'; +import {getTotalCoins} from './getTotalCoins'; import {startMiningSession} from './startMiningSession'; import {startOrUpdatePreStaking} from './startOrUpdatePreStaking'; @@ -18,4 +19,5 @@ export const tokenomics = Object.freeze({ getBalanceHistory, startOrUpdatePreStaking, claimExtraBonus, + getTotalCoins, }); diff --git a/src/api/tokenomics/types.ts b/src/api/tokenomics/types.ts index 9d06fe94b..bbb57239b 100644 --- a/src/api/tokenomics/types.ts +++ b/src/api/tokenomics/types.ts @@ -82,3 +82,19 @@ export type EthDistributionKycStep = 5; export type SocialKycStepNumber = | VerifySocialAccountKycStep | EthDistributionKycStep; + +export type TotalCoins = { + blockchain: number; + preStaking: number; + standard: number; + total: number; + timeSeries: TotalCoinsTimeSeries[]; +}; + +export type TotalCoinsTimeSeries = { + date: string; // "2022-11-30T16:35:02.996090946Z", + blockchain: number; + preStaking: number; + standard: number; + total: number; +}; diff --git a/src/assets/svg/CoinsStackSmallIcon.tsx b/src/assets/svg/CoinsStackSmallIcon.tsx new file mode 100644 index 000000000..623ff7e9d --- /dev/null +++ b/src/assets/svg/CoinsStackSmallIcon.tsx @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import * as React from 'react'; +import Svg, {Path, SvgProps} from 'react-native-svg'; +import {rem} from 'rn-units'; + +export const CoinsStackSmallIcon = ({ + color = COLORS.white, + width = rem(28), + height = rem(28), + ...props +}: SvgProps) => ( + + + +); diff --git a/src/components/BarGraph/components/BarLabel.tsx b/src/components/BarGraph/components/BarLabel.tsx index f849390b9..a460b1bdf 100644 --- a/src/components/BarGraph/components/BarLabel.tsx +++ b/src/components/BarGraph/components/BarLabel.tsx @@ -1,26 +1,43 @@ // SPDX-License-Identifier: ice License 1.0 +import {CoinsStackSmallIcon} from '@svg/CoinsStackSmallIcon'; import {TierOneIcon} from '@svg/TierOneIcon'; import {font} from '@utils/styles'; import React from 'react'; import {StyleSheet, Text, View} from 'react-native'; import {rem} from 'rn-units'; +export type StatsType = 'active_users' | 'total_coins'; + type Props = { value: string; color: string; + type?: StatsType; }; -export const BarLabel = ({value, color}: Props) => { +export const BarLabel = ({value, color, type = 'active_users'}: Props) => { return ( - - + {type === 'total_coins' && ( + + )} + {type === 'active_users' && ( + <> + + + + )} + {value} ); diff --git a/src/components/BarGraph/components/HorizontalBar.tsx b/src/components/BarGraph/components/HorizontalBar.tsx index 13188d246..a3977a180 100644 --- a/src/components/BarGraph/components/HorizontalBar.tsx +++ b/src/components/BarGraph/components/HorizontalBar.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {BarLabel} from '@components/BarGraph/components/BarLabel'; +import {BarLabel, StatsType} from '@components/BarGraph/components/BarLabel'; import {COLORS} from '@constants/colors'; import {isRTL} from '@translations/i18n'; import {formatNumber} from '@utils/numbers'; @@ -19,6 +19,7 @@ type Props = { maxWidth: number; sharedValue: SharedValue; doAnimate: boolean; + type?: StatsType; }; export const HorizontalBar = ({ @@ -27,6 +28,7 @@ export const HorizontalBar = ({ value, sharedValue, doAnimate, + type, }: Props) => { const isLabelOutside = value / maxValue < 0.2; const width = useMemo( @@ -74,10 +76,12 @@ export const HorizontalBar = ({ doAnimate && animatedStyle, {width}, ]}> - {!isLabelOutside && } + {!isLabelOutside && ( + + )} {isLabelOutside && ( - + )} ); diff --git a/src/components/BarGraph/hooks/useGetTotalCoinsBarGraphDataForStatsPeriod.ts b/src/components/BarGraph/hooks/useGetTotalCoinsBarGraphDataForStatsPeriod.ts new file mode 100644 index 000000000..fb8eab785 --- /dev/null +++ b/src/components/BarGraph/hooks/useGetTotalCoinsBarGraphDataForStatsPeriod.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {totalCoinsToGraphData} from '@components/BarGraph/utils/totalCoinsToGraphData'; +import {isSplashHiddenSelector} from '@store/modules/AppCommon/selectors'; +import {StatsPeriod} from '@store/modules/Stats/types'; +import {TokenomicsActions} from '@store/modules/Tokenomics/actions'; +import {getTotalCoinsStatsSelector} from '@store/modules/Tokenomics/selectors'; +import {TotalCoinsBarGraphData} from '@store/modules/Tokenomics/types'; +import {useEffect, useMemo} from 'react'; +import {useDispatch, useSelector} from 'react-redux'; + +export function useGetTotalCoinsBarGraphDataForStatsPeriod( + statsPeriod: StatsPeriod, +): TotalCoinsBarGraphData { + const timeSeries = useSelector(getTotalCoinsStatsSelector(statsPeriod)); + const isSplashHidden = useSelector(isSplashHiddenSelector); + + const totalCoinsBarGraphData: TotalCoinsBarGraphData = useMemo(() => { + return totalCoinsToGraphData({ + timeSeries, + }); + }, [timeSeries]); + + const dispatch = useDispatch(); + useEffect(() => { + if (isSplashHidden) { + dispatch( + TokenomicsActions.GET_TOTAL_COINS_STATS.START.create(statsPeriod), + ); + } + }, [dispatch, statsPeriod, isSplashHidden]); + + return totalCoinsBarGraphData; +} diff --git a/src/components/BarGraph/hooks/useGetBarGraphDataForStatsPeriod.ts b/src/components/BarGraph/hooks/useGetUserGrowthBarGraphDataForStatsPeriod.ts similarity index 83% rename from src/components/BarGraph/hooks/useGetBarGraphDataForStatsPeriod.ts rename to src/components/BarGraph/hooks/useGetUserGrowthBarGraphDataForStatsPeriod.ts index db459dc2e..e04a3ec0d 100644 --- a/src/components/BarGraph/hooks/useGetBarGraphDataForStatsPeriod.ts +++ b/src/components/BarGraph/hooks/useGetUserGrowthBarGraphDataForStatsPeriod.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {timeSeriesToUsersData} from '@components/BarGraph/utils/timeSeriesToGraphData'; +import {timeSeriesToUsersGraphData} from '@components/BarGraph/utils/timeSeriesToUsersGraphData'; import {isSplashHiddenSelector} from '@store/modules/AppCommon/selectors'; import {StatsActions} from '@store/modules/Stats/actions'; import {getUserGrowthStatsSelector} from '@store/modules/Stats/selectors'; @@ -8,14 +8,14 @@ import {StatsPeriod, UsersBarGraphData} from '@store/modules/Stats/types'; import {useEffect, useMemo} from 'react'; import {useDispatch, useSelector} from 'react-redux'; -export function useGetBarGraphDataForStatsPeriod( +export function useGetUserGrowthBarGraphDataForStatsPeriod( statsPeriod: StatsPeriod, ): UsersBarGraphData { const timeSeries = useSelector(getUserGrowthStatsSelector(statsPeriod)); const isSplashHidden = useSelector(isSplashHiddenSelector); const usersBarGraphData: UsersBarGraphData = useMemo(() => { - return timeSeriesToUsersData({ + return timeSeriesToUsersGraphData({ timeSeries, }); }, [timeSeries]); diff --git a/src/components/BarGraph/index.tsx b/src/components/BarGraph/index.tsx index f6c1d9975..03c69bebb 100644 --- a/src/components/BarGraph/index.tsx +++ b/src/components/BarGraph/index.tsx @@ -1,5 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 +import {StatsType} from '@components/BarGraph/components/BarLabel'; import {HorizontalBar} from '@components/BarGraph/components/HorizontalBar'; import {BarGraphData} from '@components/BarGraph/types'; import {useScreenTransitionEnd} from '@navigation/hooks/useScreenTransitionEnd'; @@ -64,6 +65,7 @@ type BarItemProps = { maxValue: number; sharedValue: SharedValue; doAnimate: boolean; + type?: StatsType; }; export const BarItem = memo( @@ -73,6 +75,7 @@ export const BarItem = memo( sharedValue, maxValue, doAnimate, + type, }: BarItemProps) => { return ( @@ -83,6 +86,7 @@ export const BarItem = memo( value={value} sharedValue={sharedValue} doAnimate={doAnimate} + type={type} /> ); diff --git a/src/components/BarGraph/utils/timeSeriesToGraphData.ts b/src/components/BarGraph/utils/timeSeriesToUsersGraphData.ts similarity index 83% rename from src/components/BarGraph/utils/timeSeriesToGraphData.ts rename to src/components/BarGraph/utils/timeSeriesToUsersGraphData.ts index 0f754fd5a..18db4bb02 100644 --- a/src/components/BarGraph/utils/timeSeriesToGraphData.ts +++ b/src/components/BarGraph/utils/timeSeriesToUsersGraphData.ts @@ -1,14 +1,14 @@ // SPDX-License-Identifier: ice License 1.0 -import {TimeSeries} from '@api/statistics/types'; +import {UserGrowthTimeSeries} from '@api/statistics/types'; import {BarGraphData} from '@components/BarGraph/types'; import {dayjs} from '@services/dayjs'; import {UsersBarGraphData} from '@store/modules/Stats/types'; -export function timeSeriesToUsersData({ +export function timeSeriesToUsersGraphData({ timeSeries, }: { - timeSeries: TimeSeries[]; + timeSeries: UserGrowthTimeSeries[]; }): UsersBarGraphData { if (!timeSeries?.length) { return { diff --git a/src/components/BarGraph/utils/totalCoinsToGraphData.ts b/src/components/BarGraph/utils/totalCoinsToGraphData.ts new file mode 100644 index 000000000..f99ea8b8f --- /dev/null +++ b/src/components/BarGraph/utils/totalCoinsToGraphData.ts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {TotalCoinsTimeSeries} from '@api/tokenomics/types'; +import {BarGraphData} from '@components/BarGraph/types'; +import {dayjs} from '@services/dayjs'; +import {TotalCoinsBarGraphData} from '@store/modules/Tokenomics/types'; + +export function totalCoinsToGraphData({ + timeSeries, +}: { + timeSeries: TotalCoinsTimeSeries[]; +}): TotalCoinsBarGraphData { + if (!timeSeries?.length) { + return { + blockchainData: [], + preStakingData: [], + standardData: [], + totalData: [], + }; + } + + const blockchainData: BarGraphData[] = timeSeries.map( + ({date, blockchain}) => { + return { + label: dayjs(date).format('MM/DD'), + value: blockchain, + }; + }, + ); + + const preStakingData: BarGraphData[] = timeSeries.map( + ({date, preStaking}) => { + return { + label: dayjs(date).format('MM/DD'), + value: preStaking, + }; + }, + ); + + const standardData: BarGraphData[] = timeSeries.map(({date, standard}) => { + return { + label: dayjs(date).format('MM/DD'), + value: standard, + }; + }); + + const totalData: BarGraphData[] = timeSeries.map(({date, total}) => { + return { + label: dayjs(date).format('MM/DD'), + value: total, + }; + }); + + return { + blockchainData, + preStakingData, + standardData, + totalData, + }; +} diff --git a/src/screens/HomeFlow/BalanceHistory/components/Filters/components/FilterButton.tsx b/src/components/Buttons/FilterButton/index.tsx similarity index 100% rename from src/screens/HomeFlow/BalanceHistory/components/Filters/components/FilterButton.tsx rename to src/components/Buttons/FilterButton/index.tsx diff --git a/src/screens/HomeFlow/Stats/components/UsersGrowthGraph/components/PeriodSelect/index.tsx b/src/components/Menu/DropDownMenu/index.tsx similarity index 97% rename from src/screens/HomeFlow/Stats/components/UsersGrowthGraph/components/PeriodSelect/index.tsx rename to src/components/Menu/DropDownMenu/index.tsx index 2b62987b5..e65135ad2 100644 --- a/src/screens/HomeFlow/Stats/components/UsersGrowthGraph/components/PeriodSelect/index.tsx +++ b/src/components/Menu/DropDownMenu/index.tsx @@ -19,7 +19,7 @@ type Props = { onChange: (index: number) => void; }; -export const PeriodSelect = ({selectedIndex, options, onChange}: Props) => { +export const DropDownMenu = ({selectedIndex, options, onChange}: Props) => { const navigation = useNavigation>(); const buttonRef = useRef(null); diff --git a/src/navigation/Main.tsx b/src/navigation/Main.tsx index 4643d7351..f8b4ebaa2 100644 --- a/src/navigation/Main.tsx +++ b/src/navigation/Main.tsx @@ -31,7 +31,6 @@ import { } from '@screens/HomeFlow/Home/types'; import {InAppNotifications} from '@screens/HomeFlow/InAppNotifications'; import {Stats} from '@screens/HomeFlow/Stats'; -import {TopCountries} from '@screens/HomeFlow/TopCountries'; import {TopMiners} from '@screens/HomeFlow/TopMiners'; import {UserGrowthGraph} from '@screens/HomeFlow/UserGrowthGraph'; import {ImageView} from '@screens/ImageView'; @@ -162,6 +161,7 @@ export type MainStackParamList = { hostViewParams: ViewMeasurementsResult; correctiveOffset?: number; }; + TopMiners: undefined; }; export type HomeTabStackParamList = { @@ -173,8 +173,6 @@ export type HomeTabStackParamList = { } | undefined; Stats: undefined; - TopMiners: undefined; - TopCountries: undefined; UserGrowthGraph: { category: 'active' | 'total'; statsPeriod: StatsPeriod; @@ -229,8 +227,6 @@ const HomeTabStackNavigator = () => ( - - @@ -457,6 +453,7 @@ export function MainNavigator() { component={VerifiedTooltipPopUp} options={modalOptions} /> + ); } diff --git a/src/screens/HomeFlow/BalanceHistory/components/Filters/index.tsx b/src/screens/HomeFlow/BalanceHistory/components/Filters/index.tsx index 6ea854580..64404e59e 100644 --- a/src/screens/HomeFlow/BalanceHistory/components/Filters/index.tsx +++ b/src/screens/HomeFlow/BalanceHistory/components/Filters/index.tsx @@ -1,15 +1,15 @@ // SPDX-License-Identifier: ice License 1.0 +import { + FilterButton, + FilterButtonDivider, +} from '@components/Buttons/FilterButton'; import {COLORS} from '@constants/colors'; import {commonStyles} from '@constants/styles'; import {useScrollShadow} from '@hooks/useScrollShadow'; import {MainNavigationParams} from '@navigation/Main'; import {useNavigation} from '@react-navigation/native'; import {NativeStackNavigationProp} from '@react-navigation/native-stack'; -import { - FilterButton, - FilterButtonDivider, -} from '@screens/HomeFlow/BalanceHistory/components/Filters/components/FilterButton'; import {ResetFilterButton} from '@screens/HomeFlow/BalanceHistory/components/Filters/components/ResetFilterButton'; import {buildDateRangeText} from '@screens/HomeFlow/BalanceHistory/components/Filters/utils/buildDateRangeText'; import {dayjs} from '@services/dayjs'; diff --git a/src/screens/HomeFlow/Home/components/Overview/components/OnlineUsersHistory/index.tsx b/src/screens/HomeFlow/Home/components/Overview/components/OnlineUsersHistory/index.tsx index abe82ee15..102c570f0 100644 --- a/src/screens/HomeFlow/Home/components/Overview/components/OnlineUsersHistory/index.tsx +++ b/src/screens/HomeFlow/Home/components/Overview/components/OnlineUsersHistory/index.tsx @@ -2,7 +2,7 @@ import {AnimatedNumberText} from '@components/AnimatedNumberText'; import {VerticalBar} from '@components/BarGraph/components/VerticalBar'; -import {useGetBarGraphDataForStatsPeriod} from '@components/BarGraph/hooks/useGetBarGraphDataForStatsPeriod'; +import {useGetUserGrowthBarGraphDataForStatsPeriod} from '@components/BarGraph/hooks/useGetUserGrowthBarGraphDataForStatsPeriod'; import {COLORS} from '@constants/colors'; import {Images} from '@images'; import { @@ -33,7 +33,7 @@ type Props = { }; export const OnlineUsersHistory = ({sharedIsCollapsed}: Props) => { - const {activeUsersData: data} = useGetBarGraphDataForStatsPeriod( + const {activeUsersData: data} = useGetUserGrowthBarGraphDataForStatsPeriod( USER_GROWTH_STATS_PERIOD, ); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/ActiveUsersGraph/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/ActiveUsersGraph/index.tsx new file mode 100644 index 000000000..fa11b509b --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/ActiveUsersGraph/index.tsx @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {useGetUserGrowthBarGraphDataForStatsPeriod} from '@components/BarGraph/hooks/useGetUserGrowthBarGraphDataForStatsPeriod'; +import {SectionHeader} from '@components/SectionHeader'; +import {commonStyles} from '@constants/styles'; +import {AnimatedGraph} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/AnimatedGraph'; +import {StatsPeriodSelector} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/StatsPeriodSelector'; +import {TopMiners} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopMiners'; +import {StatsPeriod} from '@store/modules/Stats/types'; +import {t} from '@translations/i18n'; +import React, {memo, useState} from 'react'; +import {StyleSheet, View} from 'react-native'; +import {rem} from 'rn-units'; + +export const DEFAULT_PERIOD = 7; + +export const ActiveUsersGraph = memo(() => { + const [period, setPeriod] = useState(DEFAULT_PERIOD); + const {activeUsersData} = useGetUserGrowthBarGraphDataForStatsPeriod(period); + + return ( + + + } + /> + } + ListFooter={} + /> + + ); +}); + +const styles = StyleSheet.create({ + sectionHeader: { + marginBottom: rem(10), + }, +}); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/AnimatedGraph/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/AnimatedGraph/index.tsx new file mode 100644 index 000000000..ea228ee46 --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/AnimatedGraph/index.tsx @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: ice License 1.0 + +import { + BarFooter, + BarItem, + getValueData, + ROW_HEIGHT, + Y_AXIS_WIDTH, +} from '@components/BarGraph'; +import {StatsType} from '@components/BarGraph/components/BarLabel'; +import {BarGraphData} from '@components/BarGraph/types'; +import {SCREEN_SIDE_OFFSET, windowWidth} from '@constants/styles'; +import {useBottomTabBarOffsetStyle} from '@navigation/hooks/useBottomTabBarOffsetStyle'; +import {useScreenTransitionEnd} from '@navigation/hooks/useScreenTransitionEnd'; +import React, { + ComponentType, + memo, + ReactElement, + useEffect, + useMemo, +} from 'react'; +import {StyleSheet} from 'react-native'; +import Animated, {useSharedValue, withTiming} from 'react-native-reanimated'; +import {screenHeight} from 'rn-units'; + +type Props = { + data: BarGraphData[]; + ListHeader?: ComponentType | ReactElement; + ListFooter?: ComponentType | ReactElement; + type?: StatsType; +}; + +export const AnimatedGraph = memo( + ({data, ListHeader, ListFooter, type}: Props) => { + const tabbarOffset = useBottomTabBarOffsetStyle(); + const {transitionEnd} = useScreenTransitionEnd(); + const {stepValue, lastXValue, numberOfSteps} = useMemo( + () => getValueData(data), + [data], + ); + + const barWidth = windowWidth - Y_AXIS_WIDTH - SCREEN_SIDE_OFFSET * 2; + const sharedValue = useSharedValue(-1); + + const lastElement = data[data.length - 1]; + + useEffect(() => { + if (transitionEnd && lastElement?.value != null && data.length) { + sharedValue.value = -1; + const handle = requestAnimationFrame(() => { + sharedValue.value = withTiming(0, {duration: 300}); + }); + return () => cancelAnimationFrame(handle); + } + }, [transitionEnd, lastElement?.value, data.length, sharedValue]); + + return ( + ( + index} + type={type} + /> + )} + ListFooterComponent={ + <> + + {ListFooter} + + } + ListHeaderComponent={ListHeader} + /> + ); + }, +); + +const getItemLayout = (_: unknown, index: number) => ({ + length: ROW_HEIGHT, + offset: ROW_HEIGHT * index, + index, +}); + +const styles = StyleSheet.create({ + contentContainer: { + paddingHorizontal: SCREEN_SIDE_OFFSET, + flexGrow: 1, + }, + header: { + marginLeft: -SCREEN_SIDE_OFFSET, + marginRight: -SCREEN_SIDE_OFFSET, + }, +}); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/StatsPeriodSelector/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/StatsPeriodSelector/index.tsx new file mode 100644 index 000000000..15e9163cd --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/StatsPeriodSelector/index.tsx @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {DropDownMenu} from '@components/Menu/DropDownMenu'; +import {STATS_PERIODS} from '@store/modules/Stats/constants'; +import {StatsPeriod} from '@store/modules/Stats/types'; +import {t} from '@translations/i18n'; +import React from 'react'; + +const PERIODS = STATS_PERIODS.map(period => ({ + label: t(`periods.${period}_days`), + period, +})); + +type Props = { + selectedPeriod: StatsPeriod; + onChange: (period: StatsPeriod) => void; +}; + +export const StatsPeriodSelector = ({selectedPeriod, onChange}: Props) => { + return ( + onChange(STATS_PERIODS[index])} + /> + ); +}; diff --git a/src/screens/HomeFlow/Stats/components/TopCountries/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopCountries/index.tsx similarity index 95% rename from src/screens/HomeFlow/Stats/components/TopCountries/index.tsx rename to src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopCountries/index.tsx index 0bdef35e4..fa4b7561f 100644 --- a/src/screens/HomeFlow/Stats/components/TopCountries/index.tsx +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopCountries/index.tsx @@ -22,12 +22,16 @@ const SKELETONS = Array(COUNTRIES_COUNT) .fill(null) .map((_, index) => ); +/** + * Not used + */ export const TopCountries = memo(() => { const navigation = useNavigation>(); const onSeeAllPress = useCallback(() => { - navigation.navigate('TopCountries'); + // navigation.navigate('TopCountries'); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [navigation]); const {data, fetch, hasNext} = useFetchCollection({ diff --git a/src/screens/HomeFlow/Stats/components/TopMiners/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopMiners/index.tsx similarity index 96% rename from src/screens/HomeFlow/Stats/components/TopMiners/index.tsx rename to src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopMiners/index.tsx index 3c83b80a8..48c64961f 100644 --- a/src/screens/HomeFlow/Stats/components/TopMiners/index.tsx +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TopMiners/index.tsx @@ -5,7 +5,6 @@ import {ListItemSkeleton} from '@components/ListItems/ListItemSkeleton'; import {UserListItemCompact} from '@components/ListItems/UserListItemCompact'; import {SectionHeader} from '@components/SectionHeader'; import {Touchable} from '@components/Touchable'; -import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {useFetchCollection} from '@hooks/useFetchCollection'; import {MainNavigationParams} from '@navigation/Main'; import {useNavigation} from '@react-navigation/native'; @@ -61,6 +60,7 @@ export const TopMiners = memo(() => { title={t('stats.top_miners')} action={t('button.see_all')} onActionPress={onSeeAllPress} + style={styles.header} /> {hasNext && !displayData.length @@ -91,6 +91,8 @@ const styles = StyleSheet.create({ }, list: { marginTop: rem(4), - marginHorizontal: SCREEN_SIDE_OFFSET, + }, + header: { + marginHorizontal: 0, }, }); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/components/TotalCoinsFilters/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/components/TotalCoinsFilters/index.tsx new file mode 100644 index 000000000..6c00f677d --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/components/TotalCoinsFilters/index.tsx @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {TotalCoinsFilter} from '@api/statistics/types'; +import {FilterButton} from '@components/Buttons/FilterButton'; +import {t} from '@translations/i18n'; +import React from 'react'; +import {StyleSheet} from 'react-native'; +import {ScrollView} from 'react-native-gesture-handler'; +import {rem} from 'rn-units'; + +type Props = { + onSelect: (filter: TotalCoinsFilter) => void; + selectedFilter: TotalCoinsFilter; +}; + +export type Filter = { + type: TotalCoinsFilter; + label: string; +}; + +export const FILTERS: Filter[] = [ + {type: 'total', label: t('stats.filter.total')}, + {type: 'on-app', label: t('stats.filter.on_app')}, + {type: 'pre-staked', label: t('stats.filter.pre_staked')}, + {type: 'on-blockchain', label: t('stats.filter.on_blockchain')}, +]; + +export const TotalCoinsFilters = ({onSelect, selectedFilter}: Props) => { + return ( + + {FILTERS.map(filter => { + return ( + onSelect(filter.type)} + label={filter.label} + preset={'light'} + selected={selectedFilter === filter.type} + /> + ); + })} + + ); +}; + +const styles = StyleSheet.create({ + scrollContent: { + flexGrow: 0, + paddingHorizontal: rem(12), + paddingTop: rem(18), + paddingBottom: rem(6), + }, +}); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/index.tsx new file mode 100644 index 000000000..d3c047f63 --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/index.tsx @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {TotalCoinsFilter} from '@api/statistics/types'; +import {useGetTotalCoinsBarGraphDataForStatsPeriod} from '@components/BarGraph/hooks/useGetTotalCoinsBarGraphDataForStatsPeriod'; +import {BarGraphData} from '@components/BarGraph/types'; +import {SectionHeader} from '@components/SectionHeader'; +import {AnimatedGraph} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/AnimatedGraph'; +import {StatsPeriodSelector} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/StatsPeriodSelector'; +import {TotalCoinsFilters} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph/components/TotalCoinsFilters'; +import {StatsPeriod} from '@store/modules/Stats/types'; +import {t} from '@translations/i18n'; +import React, {memo, useMemo, useState} from 'react'; +import {StyleSheet, View} from 'react-native'; +import {rem} from 'rn-units'; + +export const DEFAULT_PERIOD = 7; +export const DEFAULT_FILTER = 'total'; + +export const TotalCoinsGraph = memo(() => { + const [period, setPeriod] = useState(DEFAULT_PERIOD); + const [filter, setFilter] = useState(DEFAULT_FILTER); + const {totalData, blockchainData, standardData, preStakingData} = + useGetTotalCoinsBarGraphDataForStatsPeriod(period); + + const dataForFilter: BarGraphData[] = useMemo(() => { + switch (filter) { + case 'total': + return totalData; + case 'on-app': + return standardData; + case 'on-blockchain': + return blockchainData; + case 'pre-staked': + return preStakingData; + } + }, [blockchainData, filter, preStakingData, standardData, totalData]); + + return ( + + + } + /> + + + } + type="total_coins" + /> + ); +}); + +const styles = StyleSheet.create({ + listHeader: { + marginBottom: rem(10), + }, +}); diff --git a/src/screens/HomeFlow/Stats/components/SegmentedGraphs/index.tsx b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/index.tsx new file mode 100644 index 000000000..27ebd1fee --- /dev/null +++ b/src/screens/HomeFlow/Stats/components/SegmentedGraphs/index.tsx @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: ice License 1.0 + +import { + SegmentedControl, + SegmentedControlMethods, +} from '@components/SegmentedControl'; +import {commonStyles} from '@constants/styles'; +import {ActiveUsersGraph} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/ActiveUsersGraph'; +import {TotalCoinsGraph} from '@screens/HomeFlow/Stats/components/SegmentedGraphs/components/TotalCoinsGraph'; +import {t} from '@translations/i18n'; +import React, {memo, useCallback, useRef} from 'react'; +import {StyleSheet, View} from 'react-native'; +import PagerView, {PagerViewOnPageSelectedEvent} from 'react-native-pager-view'; +import {rem} from 'rn-units'; + +export const SEGMENTS = [ + {text: t('stats.active'), key: 'active_users'}, + {text: t('stats.total_coins'), key: 'total_coins'}, +] as const; + +export const SegmentedGraphs = memo(() => { + const switcherRef = useRef(null); + const pagerRef = useRef(null); + + const onSegmentChange = useCallback((index: number) => { + pagerRef.current?.setPage(index); + }, []); + + const onPageChange = (event: PagerViewOnPageSelectedEvent) => { + const index = event.nativeEvent.position; + switcherRef.current?.changeSegment(index); + }; + + return ( + + + + + + + + ); +}); + +const styles = StyleSheet.create({ + segmentSwitcher: { + marginTop: rem(20), + marginHorizontal: rem(20), + }, +}); diff --git a/src/screens/HomeFlow/Stats/components/Summary/index.tsx b/src/screens/HomeFlow/Stats/components/Summary/index.tsx index ebc33fe41..7316164be 100644 --- a/src/screens/HomeFlow/Stats/components/Summary/index.tsx +++ b/src/screens/HomeFlow/Stats/components/Summary/index.tsx @@ -1,13 +1,11 @@ // SPDX-License-Identifier: ice License 1.0 import {COLORS} from '@constants/colors'; -import { - totalActiveUsersSelector, - totalUsersSelector, -} from '@store/modules/Stats/selectors'; +import {totalActiveUsersSelector} from '@store/modules/Stats/selectors'; +import {totalCoinsSelector} from '@store/modules/Tokenomics/selectors'; +import {CoinsStackSmallIcon} from '@svg/CoinsStackSmallIcon'; import {LogoIcon} from '@svg/LogoIcon'; -import {TeamInactiveIcon} from '@svg/TeamInactiveIcon'; -import {isRTL, t} from '@translations/i18n'; +import {t} from '@translations/i18n'; import {formatNumber} from '@utils/numbers'; import {font} from '@utils/styles'; import React, {memo} from 'react'; @@ -17,35 +15,31 @@ import {rem} from 'rn-units'; export const Summary = memo(() => { const totalActiveUsers = useSelector(totalActiveUsersSelector); - const totalUsers = useSelector(totalUsersSelector); + const totalCoins = useSelector(totalCoinsSelector); return ( - {t('stats.online_miners')} + {t('stats.active')} {formatNumber(totalActiveUsers)} - + - - + + - - {t('stats.total')} - - - {formatNumber(totalUsers)} + {t('stats.total_coins')} + + {formatNumber(totalCoins, { + notation: 'compact', + maximumFractionDigits: 1, + })} @@ -53,25 +47,27 @@ export const Summary = memo(() => { ); }); +const ONLINE_INDICATOR_SIZE = rem(6); + const styles = StyleSheet.create({ container: { - paddingTop: rem(4), - paddingBottom: rem(16), + marginTop: rem(4), + marginBottom: rem(16), flexDirection: 'row', - alignItems: 'flex-end', - width: '100%', + alignItems: 'center', }, cell: { flexDirection: 'row', - alignItems: 'flex-end', + alignItems: 'center', width: '50%', paddingHorizontal: rem(24), }, - cell_right: { + cellRight: { justifyContent: 'flex-end', + paddingEnd: rem(26), }, cellData: { - marginLeft: rem(12), + marginStart: rem(8), flexShrink: 1, }, separator: { @@ -80,26 +76,23 @@ const styles = StyleSheet.create({ backgroundColor: COLORS.white, }, labelText: { - ...font(12, 16, 'medium'), + ...font(12, 14.4), opacity: 0.7, }, value: { + marginTop: rem(1), flexDirection: 'row', alignItems: 'flex-start', }, valueText: { - ...font(15, 20, 'black'), + ...font(15, 18, 'black'), alignItems: 'flex-end', }, onlineIndicator: { - ...font(15, null, 'black', 'shamrock'), - marginTop: -rem(7), marginLeft: rem(2), - }, - teamIcon: { - marginBottom: -rem(5), - }, - textAlignRight: { - textAlign: isRTL ? 'left' : 'right', + backgroundColor: COLORS.shamrock, + width: ONLINE_INDICATOR_SIZE, + height: ONLINE_INDICATOR_SIZE, + borderRadius: ONLINE_INDICATOR_SIZE / 2, }, }); diff --git a/src/screens/HomeFlow/Stats/components/UsersGrowthGraph/index.tsx b/src/screens/HomeFlow/Stats/components/UsersGrowthGraph/index.tsx deleted file mode 100644 index 540119178..000000000 --- a/src/screens/HomeFlow/Stats/components/UsersGrowthGraph/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import {BarGraph, getBarGraphHeight} from '@components/BarGraph'; -import {useGetBarGraphDataForStatsPeriod} from '@components/BarGraph/hooks/useGetBarGraphDataForStatsPeriod'; -import {SectionHeader} from '@components/SectionHeader'; -import { - SegmentedControl, - SegmentedControlMethods, -} from '@components/SegmentedControl'; -import {HomeTabStackParamList} from '@navigation/Main'; -import {useNavigation} from '@react-navigation/native'; -import {NativeStackNavigationProp} from '@react-navigation/native-stack'; -import {t} from '@translations/i18n'; -import React, {memo, useCallback, useRef} from 'react'; -import {StyleSheet, View} from 'react-native'; -import PagerView, {PagerViewOnPageSelectedEvent} from 'react-native-pager-view'; -import {rem} from 'rn-units'; - -type GraphCategory = 'total' | 'active'; - -export const SEGMENTS: ReadonlyArray<{text: string; key: GraphCategory}> = [ - {text: t('stats.total'), key: 'total'}, - {text: t('stats.active'), key: 'active'}, -]; - -export const DEFAULT_USER_GROWTH_STATS_PERIOD = 3; - -export const UsersGrowthGraph = memo(() => { - const navigation = - useNavigation>(); - const switcherRef = useRef(null); - const pagerRef = useRef(null); - const segmentRef = useRef(SEGMENTS[0]); - - const onSegmentChange = useCallback((index: number) => { - segmentRef.current = SEGMENTS[index]; - pagerRef.current?.setPage(index); - }, []); - - const onPageChange = (event: PagerViewOnPageSelectedEvent) => { - const index = event.nativeEvent.position; - segmentRef.current = SEGMENTS[index]; - switcherRef.current?.changeSegment(index); - }; - - const onSeeAll = () => { - navigation.navigate('UserGrowthGraph', { - category: segmentRef.current.key, - statsPeriod: DEFAULT_USER_GROWTH_STATS_PERIOD, - }); - }; - - const {activeUsersData, totalUsersData} = useGetBarGraphDataForStatsPeriod( - DEFAULT_USER_GROWTH_STATS_PERIOD, - ); - - return ( - - - - - - - - - - - - - ); -}); - -const styles = StyleSheet.create({ - segmentSwitcher: { - marginTop: rem(20), - marginHorizontal: rem(20), - }, - sectionHeaderChevron: { - transform: [{rotate: '180deg'}], - marginLeft: rem(6), - marginBottom: rem(8), - }, - segmentPager: { - marginTop: rem(12), - }, - segmentSlide: { - paddingHorizontal: rem(20), - }, -}); diff --git a/src/screens/HomeFlow/Stats/hooks/useOnRefresh.ts b/src/screens/HomeFlow/Stats/hooks/useOnRefresh.ts deleted file mode 100644 index 584c9da93..000000000 --- a/src/screens/HomeFlow/Stats/hooks/useOnRefresh.ts +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import {COUNTRIES_COUNT} from '@screens/HomeFlow/Stats/components/TopCountries'; -import {MINERS_COUNT} from '@screens/HomeFlow/Stats/components/TopMiners'; -import {DEFAULT_USER_GROWTH_STATS_PERIOD} from '@screens/HomeFlow/Stats/components/UsersGrowthGraph'; -import {CollectionActions} from '@store/modules/Collections'; -import {StatsActions} from '@store/modules/Stats/actions'; -import {isLoadingSelector} from '@store/modules/UtilityProcessStatuses/selectors'; -import {RootState} from '@store/rootReducer'; -import {useCallback, useEffect} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; - -export function useOnRefresh() { - const dispatch = useDispatch(); - - const refreshing = useSelector( - (state: RootState) => - isLoadingSelector(StatsActions.GET_USER_GROWTH_STATS, state) || - isLoadingSelector(CollectionActions.GET_TOP_MINERS, state) || - isLoadingSelector(CollectionActions.GET_TOP_STATS_COUNTRIES, state), - ); - - const onRefresh = useCallback(() => { - dispatch( - StatsActions.GET_USER_GROWTH_STATS.START.create( - DEFAULT_USER_GROWTH_STATS_PERIOD, - ), - ); - - dispatch( - CollectionActions.GET_TOP_MINERS.START.create({ - isInitial: true, - limit: MINERS_COUNT, - }), - ); - - dispatch( - CollectionActions.GET_TOP_STATS_COUNTRIES.START.create({ - isInitial: true, - limit: COUNTRIES_COUNT, - }), - ); - }, [dispatch]); - - useEffect(onRefresh, [onRefresh]); - - return { - refreshing, - onRefresh, - }; -} diff --git a/src/screens/HomeFlow/Stats/index.tsx b/src/screens/HomeFlow/Stats/index.tsx index 900d94fc0..11f397632 100644 --- a/src/screens/HomeFlow/Stats/index.tsx +++ b/src/screens/HomeFlow/Stats/index.tsx @@ -1,60 +1,31 @@ // SPDX-License-Identifier: ice License 1.0 import {LinesBackground} from '@components/LinesBackground'; -import {PullToRefreshContainer} from '@components/PullToRefreshContainer'; import {COLORS} from '@constants/colors'; import {commonStyles} from '@constants/styles'; import {Header} from '@navigation/components/Header'; -import {useBottomTabBarOffsetStyle} from '@navigation/hooks/useBottomTabBarOffsetStyle'; import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; +import {SegmentedGraphs} from '@screens/HomeFlow/Stats/components/SegmentedGraphs'; import {Summary} from '@screens/HomeFlow/Stats/components/Summary'; -import {TopCountries} from '@screens/HomeFlow/Stats/components/TopCountries'; -import {TopMiners} from '@screens/HomeFlow/Stats/components/TopMiners'; -import {UsersGrowthGraph} from '@screens/HomeFlow/Stats/components/UsersGrowthGraph'; import {t} from '@translations/i18n'; import React, {memo} from 'react'; import {StyleSheet, View} from 'react-native'; -import Animated from 'react-native-reanimated'; - -import {useOnRefresh} from './hooks/useOnRefresh'; export const Stats = memo(() => { useFocusStatusBar({style: 'light-content'}); - const tabbarOffset = useBottomTabBarOffsetStyle(); - - const {refreshing, onRefresh} = useOnRefresh(); - return ( -
- - - - - - - - - - - + + + ); }); diff --git a/src/screens/HomeFlow/TopCountries/index.tsx b/src/screens/HomeFlow/TopCountries/index.tsx index bcc175bc3..755bcdece 100644 --- a/src/screens/HomeFlow/TopCountries/index.tsx +++ b/src/screens/HomeFlow/TopCountries/index.tsx @@ -8,6 +8,9 @@ import {collectionSelector} from '@store/modules/Collections/selectors'; import {t} from '@translations/i18n'; import React, {memo} from 'react'; +/** + * Not used + */ export const TopCountries = memo(() => { return ( ({label: t(`periods.${period}_days`), period}), ); +/** + * Not used + */ export const UserGrowthGraph = memo(() => { useFocusStatusBar({style: 'light-content'}); const tabbarOffset = useBottomTabBarOffsetStyle(); @@ -57,7 +60,7 @@ export const UserGrowthGraph = memo(() => { }, [paramsStatsPeriod]); const {activeUsersData, totalUsersData} = - useGetBarGraphDataForStatsPeriod(statsPeriod); + useGetUserGrowthBarGraphDataForStatsPeriod(statsPeriod); const handleRef = useRef<{cancel: () => void} | undefined>(); const onPeriodChange = (index: number) => { @@ -146,7 +149,7 @@ export const UserGrowthGraph = memo(() => { ({config}), + SUCCESS: (config: FeatureToggleConfig | null) => ({config}), FAILED: (errorMessage: string) => ({errorMessage}), }); diff --git a/src/store/modules/Account/reducer/index.ts b/src/store/modules/Account/reducer/index.ts index 370806750..b6ac6ae96 100644 --- a/src/store/modules/Account/reducer/index.ts +++ b/src/store/modules/Account/reducer/index.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {AuthConfig} from '@api/auth/types'; +import {FeatureToggleConfig} from '@api/auth/types'; import {User} from '@api/user/types'; import AsyncStorage from '@react-native-async-storage/async-storage'; import {SignInUserInfo} from '@services/auth/signin/types'; @@ -19,8 +19,8 @@ export interface AccountState { userInfo: SignInUserInfo | null; installReferrer: string | null; isPrivacyInfoShown: boolean; - authConfig: AuthConfig | null; ethereumAddrWarningConfirmed: boolean; + authConfig: FeatureToggleConfig | null; } type Actions = ReturnType< diff --git a/src/store/modules/Stats/reducer/index.ts b/src/store/modules/Stats/reducer/index.ts index edf7feddb..b57f72078 100644 --- a/src/store/modules/Stats/reducer/index.ts +++ b/src/store/modules/Stats/reducer/index.ts @@ -1,12 +1,12 @@ // SPDX-License-Identifier: ice License 1.0 -import {Adoption, TimeSeries} from '@api/statistics/types'; +import {Adoption, UserGrowthTimeSeries} from '@api/statistics/types'; import {StatsActions} from '@store/modules/Stats/actions'; import produce from 'immer'; export interface StatsState { userGrowth: { - timeSeriesStatsMap: {[key: number]: TimeSeries[]}; + timeSeriesStatsMap: {[key: number]: UserGrowthTimeSeries[]}; active: number; total: number; }; diff --git a/src/store/modules/Stats/sagas/getUserGrowthStats.ts b/src/store/modules/Stats/sagas/getUserGrowthStats.ts index c78b52ed6..9f9b402a0 100644 --- a/src/store/modules/Stats/sagas/getUserGrowthStats.ts +++ b/src/store/modules/Stats/sagas/getUserGrowthStats.ts @@ -20,6 +20,7 @@ export function* getUserGrowthStats( tz: getTimezoneOffset(), }, ); + yield put( StatsActions.GET_USER_GROWTH_STATS.SUCCESS.create( statsPeriod, diff --git a/src/store/modules/Stats/selectors/index.ts b/src/store/modules/Stats/selectors/index.ts index 712248d0c..a8305af91 100644 --- a/src/store/modules/Stats/selectors/index.ts +++ b/src/store/modules/Stats/selectors/index.ts @@ -1,12 +1,12 @@ // SPDX-License-Identifier: ice License 1.0 -import {TimeSeries} from '@api/statistics/types'; +import {UserGrowthTimeSeries} from '@api/statistics/types'; import {StatsPeriod} from '@store/modules/Stats/types'; import {RootState} from '@store/rootReducer'; export const getUserGrowthStatsSelector = (period: StatsPeriod) => - (state: RootState): TimeSeries[] => { + (state: RootState): UserGrowthTimeSeries[] => { return state.stats.userGrowth.timeSeriesStatsMap[period] ?? []; }; diff --git a/src/store/modules/Tokenomics/actions/index.ts b/src/store/modules/Tokenomics/actions/index.ts index c86cb341c..dbf969dd2 100644 --- a/src/store/modules/Tokenomics/actions/index.ts +++ b/src/store/modules/Tokenomics/actions/index.ts @@ -8,7 +8,9 @@ import { PreStakingSummary, RankingSummary, SocialKycStepNumber, + TotalCoins, } from '@api/tokenomics/types'; +import {StatsPeriod} from '@store/modules/Stats/types'; import {createAction} from '@store/utils/actions/createAction'; const GET_MINING_SUMMARY = createAction('GET_MINING_SUMMARY', { @@ -75,6 +77,15 @@ const CLAIM_DAILY_BONUS = createAction('CLAIM_DAILY_BONUS', { STATE: true, }); +const GET_TOTAL_COINS_STATS = createAction('GET_TOTAL_COINS_STATS', { + START: (statsPeriod: StatsPeriod) => ({statsPeriod}), + SUCCESS: (statsPeriod: StatsPeriod, totalCoins: TotalCoins) => ({ + statsPeriod, + totalCoins, + }), + FAILED: (errorMessage: string) => ({errorMessage}), +}); + export const TokenomicsActions = Object.freeze({ GET_MINING_SUMMARY, GET_BALANCE_SUMMARY, @@ -84,4 +95,5 @@ export const TokenomicsActions = Object.freeze({ START_MINING_SESSION, START_OR_UPDATE_PRE_STAKING, CLAIM_DAILY_BONUS, + GET_TOTAL_COINS_STATS, }); diff --git a/src/store/modules/Tokenomics/reducer/index.ts b/src/store/modules/Tokenomics/reducer/index.ts index c94d1058f..3fa11226c 100644 --- a/src/store/modules/Tokenomics/reducer/index.ts +++ b/src/store/modules/Tokenomics/reducer/index.ts @@ -6,6 +6,7 @@ import { MiningSummary, PreStakingSummary, RankingSummary, + TotalCoinsTimeSeries, } from '@api/tokenomics/types'; import {AccountActions} from '@store/modules/Account/actions'; import {TokenomicsActions} from '@store/modules/Tokenomics/actions'; @@ -26,9 +27,17 @@ export interface State { pageNumber: number; }; tapToMineActionType?: 'Extended' | 'Default'; + totalCoins: { + timeSeriesStatsMap: {[key: number]: TotalCoinsTimeSeries[]}; + blockchain: number; + preStaking: number; + standard: number; + total: number; + }; } type Actions = ReturnType< + | typeof TokenomicsActions.GET_TOTAL_COINS_STATS.SUCCESS.create | typeof TokenomicsActions.GET_MINING_SUMMARY.SUCCESS.create | typeof TokenomicsActions.START_MINING_SESSION.START.create | typeof TokenomicsActions.START_MINING_SESSION.SUCCESS.create @@ -53,11 +62,28 @@ const INITIAL_STATE: State = { endDate: null, pageNumber: 0, }, + totalCoins: { + timeSeriesStatsMap: {}, + blockchain: 0, + preStaking: 0, + standard: 0, + total: 0, + }, }; function reducer(state = INITIAL_STATE, action: Actions): State { return produce(state, draft => { switch (action.type) { + case TokenomicsActions.GET_TOTAL_COINS_STATS.SUCCESS.type: { + const {statsPeriod, totalCoins} = action.payload; + draft.totalCoins.timeSeriesStatsMap[statsPeriod] = + totalCoins.timeSeries; + draft.totalCoins.blockchain = totalCoins.blockchain; + draft.totalCoins.preStaking = totalCoins.preStaking; + draft.totalCoins.standard = totalCoins.standard; + draft.totalCoins.total = totalCoins.total; + break; + } case TokenomicsActions.START_MINING_SESSION.START.type: if (action.payload?.tapToMineActionType) { draft.tapToMineActionType = action.payload.tapToMineActionType; diff --git a/src/store/modules/Tokenomics/sagas/getTotalCoinsStats.ts b/src/store/modules/Tokenomics/sagas/getTotalCoinsStats.ts new file mode 100644 index 000000000..6d96c729e --- /dev/null +++ b/src/store/modules/Tokenomics/sagas/getTotalCoinsStats.ts @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Api} from '@api/index'; +import {TokenomicsActions} from '@store/modules/Tokenomics/actions'; +import {getTimezoneOffset} from '@utils/device'; +import {getErrorMessage} from '@utils/errors'; +import {call, put, SagaReturnType} from 'redux-saga/effects'; + +export function* getTotalCoinsStatsSaga( + action: ReturnType< + typeof TokenomicsActions.GET_TOTAL_COINS_STATS.START.create + >, +) { + const {statsPeriod} = action.payload; + try { + const { + data: totalCoins, + }: SagaReturnType = yield call( + Api.tokenomics.getTotalCoins, + { + days: statsPeriod, + tz: getTimezoneOffset(), + }, + ); + yield put( + TokenomicsActions.GET_TOTAL_COINS_STATS.SUCCESS.create( + statsPeriod, + totalCoins, + ), + ); + } catch (error) { + yield put( + TokenomicsActions.GET_TOTAL_COINS_STATS.FAILED.create( + getErrorMessage(error), + ), + ); + throw error; + } +} diff --git a/src/store/modules/Tokenomics/sagas/index.ts b/src/store/modules/Tokenomics/sagas/index.ts index efeb76e22..c497e694b 100644 --- a/src/store/modules/Tokenomics/sagas/index.ts +++ b/src/store/modules/Tokenomics/sagas/index.ts @@ -8,6 +8,7 @@ import {getBalanceSummarySaga} from '@store/modules/Tokenomics/sagas/getBalanceS import {getMiningSummarySaga} from '@store/modules/Tokenomics/sagas/getMiningSummary'; import {getPreStakingSummarySaga} from '@store/modules/Tokenomics/sagas/getPreStakingSummary'; import {getRankingSummarySaga} from '@store/modules/Tokenomics/sagas/getRankingSummary'; +import {getTotalCoinsStatsSaga} from '@store/modules/Tokenomics/sagas/getTotalCoinsStats'; import {handleExtraBonusSaga} from '@store/modules/Tokenomics/sagas/handleExtraBonus'; import {startMiningSessionSaga} from '@store/modules/Tokenomics/sagas/startMiningSession'; import {startOrUpdatePreStakingSaga} from '@store/modules/Tokenomics/sagas/startPreStaking'; @@ -72,4 +73,8 @@ export const tokenomicsWatchers = [ TokenomicsActions.CLAIM_DAILY_BONUS.STATE.type, handleExtraBonusSaga, ), + takeLatest( + TokenomicsActions.GET_TOTAL_COINS_STATS.START.type, + getTotalCoinsStatsSaga, + ), ]; diff --git a/src/store/modules/Tokenomics/selectors/index.ts b/src/store/modules/Tokenomics/selectors/index.ts index 245dbda01..fa681b5ad 100644 --- a/src/store/modules/Tokenomics/selectors/index.ts +++ b/src/store/modules/Tokenomics/selectors/index.ts @@ -1,6 +1,8 @@ // SPDX-License-Identifier: ice License 1.0 +import {TotalCoinsTimeSeries} from '@api/tokenomics/types'; import {dayjs} from '@services/dayjs'; +import {StatsPeriod} from '@store/modules/Stats/types'; import {MiningState} from '@store/modules/Tokenomics/types'; import {RootState} from '@store/rootReducer'; @@ -70,3 +72,13 @@ export const balanceHistorySelector = (state: RootState) => { export const tapToMineActionTypeSelector = (state: RootState) => { return state.tokenomics.tapToMineActionType; }; + +export const getTotalCoinsStatsSelector = + (period: StatsPeriod) => + (state: RootState): TotalCoinsTimeSeries[] => { + return state.tokenomics.totalCoins.timeSeriesStatsMap[period] ?? []; + }; + +export const totalCoinsSelector = (state: RootState) => { + return state.tokenomics.totalCoins.total; +}; diff --git a/src/store/modules/Tokenomics/types.ts b/src/store/modules/Tokenomics/types.ts index 3905b84ce..d0fb4ee15 100644 --- a/src/store/modules/Tokenomics/types.ts +++ b/src/store/modules/Tokenomics/types.ts @@ -1,5 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {BarGraphData} from '@components/BarGraph/types'; + export type MiningState = | 'inactive' | 'active' @@ -8,3 +10,10 @@ export type MiningState = | 'holidayActive' | 'holidayRestart' | 'holidayExpire'; + +export type TotalCoinsBarGraphData = { + blockchainData: BarGraphData[]; + preStakingData: BarGraphData[]; + standardData: BarGraphData[]; + totalData: BarGraphData[]; +}; diff --git a/src/translations/locales/af.json b/src/translations/locales/af.json index 44f738479..20c42b97f 100644 --- a/src/translations/locales/af.json +++ b/src/translations/locales/af.json @@ -555,7 +555,14 @@ "top_miners": "Top gebruikers", "top_countries": "Top lande", "online_miners": "Aanlyn gebruikers", - "detailed_information": "Gedetailleerde inligting" + "detailed_information": "Gedetailleerde inligting", + "total_coins": "Totale munte", + "filter": { + "total": "Totaal", + "on_app": "Beskikbaar op App", + "pre_staked": "Vooraf gestaak", + "on_blockchain": "Op die blokketting" + } }, "update_required": { "title": "Dateer asseblief op", diff --git a/src/translations/locales/am.json b/src/translations/locales/am.json index ebbd9a6e6..00d4b88bf 100644 --- a/src/translations/locales/am.json +++ b/src/translations/locales/am.json @@ -555,7 +555,14 @@ "top_miners": "ከፍተኛ ተጠቃሚዎች", "top_countries": "ከፍተኛ ሀገሮች", "online_miners": "የመስመር ላይ ተጠቃሚዎች", - "detailed_information": "ዝርዝር መረጃ" + "detailed_information": "ዝርዝር መረጃ", + "total_coins": "አጠቃቀም ማእከላዊ", + "filter": { + "total": "ጠቅላላ", + "on_app": "በመተግበሪያ ውስጥ ያሉ", + "pre_staked": "ማረጋገጫ ቀረበ", + "on_blockchain": "በብሎኬድ ላይ" + } }, "update_required": { "title": "እባክዎ ያዘምኑ", diff --git a/src/translations/locales/ar.json b/src/translations/locales/ar.json index 0b7447329..06f48a9e7 100644 --- a/src/translations/locales/ar.json +++ b/src/translations/locales/ar.json @@ -555,7 +555,14 @@ "top_miners": "أفضل المستخدمين", "top_countries": "أفضل البلدان", "online_miners": "المستخدمون عبر الإنترنت", - "detailed_information": "معلومات تفصيلية" + "detailed_information": "معلومات تفصيلية", + "total_coins": "إجمالي العملات", + "filter": { + "total": "الإجمالي", + "on_app": "متاح على التطبيق", + "pre_staked": "مرهونة مسبقاً", + "on_blockchain": "على البلوكشين" + } }, "update_required": { "title": "يُرجى التحديث", diff --git a/src/translations/locales/az.json b/src/translations/locales/az.json index df7b6b342..da24dc425 100644 --- a/src/translations/locales/az.json +++ b/src/translations/locales/az.json @@ -555,7 +555,14 @@ "top_miners": "Top istifadəçilər", "top_countries": "Top ölkələr", "online_miners": "Onlayn istifadəçilər", - "detailed_information": "Detallı məlumat" + "detailed_information": "Detallı məlumat", + "total_coins": "Ümumi kreditlər", + "filter": { + "total": "Ümumi", + "on_app": "Tətbiq üçün mövcuddur", + "pre_staked": "Əvvəlcədən stake edilmiş", + "on_blockchain": "Bloq çəkisində" + } }, "update_required": { "title": "Xahiş olunur yeniləyin ", diff --git a/src/translations/locales/bg.json b/src/translations/locales/bg.json index 3a6ea2a22..41121a097 100644 --- a/src/translations/locales/bg.json +++ b/src/translations/locales/bg.json @@ -555,7 +555,14 @@ "top_miners": "Топ потребители", "top_countries": "Топ държави", "online_miners": "Онлайн потребители", - "detailed_information": "Подробна информация" + "detailed_information": "Подробна информация", + "total_coins": "Общо монети", + "filter": { + "total": "Общо", + "on_app": "Наличен в приложението", + "pre_staked": "Предварително оценен", + "on_blockchain": "На блокчейн" + } }, "update_required": { "title": "Обновете", diff --git a/src/translations/locales/bn.json b/src/translations/locales/bn.json index ea8ba35cf..7a7804f91 100644 --- a/src/translations/locales/bn.json +++ b/src/translations/locales/bn.json @@ -555,7 +555,14 @@ "top_miners": "শীর্ষ ব্যবহারকারী", "top_countries": "শীর্ষ দেশ", "online_miners": "অনলাইন ব্যবহারকারী", - "detailed_information": "বিস্তারিত তথ্য" + "detailed_information": "বিস্তারিত তথ্য", + "total_coins": "মোট কয়েন", + "filter": { + "total": "মোট", + "on_app": "অ্যাপে উপলব্ধ", + "pre_staked": "প্রি-স্টেকড", + "on_blockchain": "ব্লকচেইনে" + } }, "update_required": { "title": "অনুগ্রহ করে আপডেট করুন", diff --git a/src/translations/locales/cs.json b/src/translations/locales/cs.json index 6a7390f97..f209e18f7 100644 --- a/src/translations/locales/cs.json +++ b/src/translations/locales/cs.json @@ -555,7 +555,14 @@ "top_miners": "Top uživatelé", "top_countries": "Top země", "online_miners": "Online uživatelé", - "detailed_information": "Podrobné informace" + "detailed_information": "Podrobné informace", + "total_coins": "Celkový počet mincí", + "filter": { + "total": "Celkem", + "on_app": "K dispozici v aplikaci", + "pre_staked": "Před-uloženo", + "on_blockchain": "Na blockchainu" + } }, "update_required": { "title": "Aktualizujte prosím", diff --git a/src/translations/locales/de.json b/src/translations/locales/de.json index 9efb5e0c3..b65bfcb1b 100644 --- a/src/translations/locales/de.json +++ b/src/translations/locales/de.json @@ -555,7 +555,14 @@ "top_miners": "Top-Nutzer", "top_countries": "Top-Länder", "online_miners": "Online-Nutzer", - "detailed_information": "Ausführliche Informationen" + "detailed_information": "Ausführliche Informationen", + "total_coins": "Gesamtmünzen", + "filter": { + "total": "Gesamt", + "on_app": "Verfügbar in der App", + "pre_staked": "Vorab gestaked", + "on_blockchain": "Auf der Blockchain" + } }, "update_required": { "title": "Bitte aktualisieren", diff --git a/src/translations/locales/el.json b/src/translations/locales/el.json index c949fb92f..f8e24c157 100644 --- a/src/translations/locales/el.json +++ b/src/translations/locales/el.json @@ -555,7 +555,14 @@ "top_miners": "Κορυφαίοι χρήστες", "top_countries": "Κορυφαίες χώρες", "online_miners": "Online χρήστες", - "detailed_information": "Λεπτομερείς πληροφορίες" + "detailed_information": "Λεπτομερείς πληροφορίες", + "total_coins": "Συνολικά κέρματα", + "filter": { + "total": "Συνολικά", + "on_app": "Διαθέσιμα στην εφαρμογή", + "pre_staked": "Προεγγυημένα", + "on_blockchain": "Στο blockchain" + } }, "update_required": { "title": "Παρακαλώ ενημερώστε", diff --git a/src/translations/locales/en.json b/src/translations/locales/en.json index 1598b4e01..d53e246e7 100644 --- a/src/translations/locales/en.json +++ b/src/translations/locales/en.json @@ -554,7 +554,14 @@ "top_miners": "Top users", "top_countries": "Top countries", "online_miners": "Online users", - "detailed_information": "Detailed information" + "detailed_information": "Detailed information", + "total_coins": "Total coins", + "filter": { + "total": "Total", + "on_app": "Available on App", + "pre_staked": "Pre-Staked", + "on_blockchain": "On Blockchain" + } }, "update_required": { "title": "Please Update", diff --git a/src/translations/locales/en.json.d.ts b/src/translations/locales/en.json.d.ts index 861da5d94..217cce91e 100644 --- a/src/translations/locales/en.json.d.ts +++ b/src/translations/locales/en.json.d.ts @@ -384,6 +384,11 @@ export type Translations = { 'stats.top_countries': null; 'stats.online_miners': null; 'stats.detailed_information': null; + 'stats.total_coins': null; + 'stats.filter.total': null; + 'stats.filter.on_app': null; + 'stats.filter.pre_staked': null; + 'stats.filter.on_blockchain': null; 'update_required.title': null; 'update_required.description': null; 'update_required.button_title': null; diff --git a/src/translations/locales/es.json b/src/translations/locales/es.json index 864f7d6d0..4a605a223 100644 --- a/src/translations/locales/es.json +++ b/src/translations/locales/es.json @@ -555,7 +555,14 @@ "top_miners": "Principales usuarios", "top_countries": "Principales países", "online_miners": "Usuarios en línea", - "detailed_information": "Información detallada" + "detailed_information": "Información detallada", + "total_coins": "Total de monedas", + "filter": { + "total": "Total", + "on_app": "Disponible en la aplicación", + "pre_staked": "Pre-staked", + "on_blockchain": "En la blockchain" + } }, "update_required": { "title": "Actualiza la versión", diff --git a/src/translations/locales/fa.json b/src/translations/locales/fa.json index 585d9f80c..be90f25c0 100644 --- a/src/translations/locales/fa.json +++ b/src/translations/locales/fa.json @@ -555,7 +555,14 @@ "top_miners": "کاربران برتر", "top_countries": "کشورهای برتر", "online_miners": "کاربران آنلاین", - "detailed_information": "اطلاعات دقیق" + "detailed_information": "اطلاعات دقیق", + "total_coins": "کل سکه‌ها", + "filter": { + "total": "کل", + "on_app": "در دسترس در برنامه", + "pre_staked": "پیش‌استیک شده", + "on_blockchain": "در بلاکچین" + } }, "update_required": { "title": "لطفاً به‌روزرسانی کنید", diff --git a/src/translations/locales/fr.json b/src/translations/locales/fr.json index 261a0b992..29e95f650 100644 --- a/src/translations/locales/fr.json +++ b/src/translations/locales/fr.json @@ -555,7 +555,14 @@ "top_miners": "Principaux utilisateurs", "top_countries": "Principaux pays", "online_miners": "Utilisateurs en ligne", - "detailed_information": "Informations détaillées" + "detailed_information": "Informations détaillées", + "total_coins": "Total des pièces", + "filter": { + "total": "Total", + "on_app": "Disponible dans l'application", + "pre_staked": "Pré-staké", + "on_blockchain": "Sur la blockchain" + } }, "update_required": { "title": "Veuillez mettre à jour", diff --git a/src/translations/locales/gu.json b/src/translations/locales/gu.json index 9999c3f24..eb2cce79f 100644 --- a/src/translations/locales/gu.json +++ b/src/translations/locales/gu.json @@ -555,7 +555,14 @@ "top_miners": "ટોચના વપરાશકર્તાઓ", "top_countries": "ટોચના દેશો", "online_miners": "ઑનલાઇન વપરાશકર્તાઓ", - "detailed_information": "વિગતવાર માહિતી" + "detailed_information": "વિગતવાર માહિતી", + "total_coins": "કુલ સિક્કો", + "filter": { + "total": "કુલ", + "on_app": "એપ્લિકેશન પર ઉપલબ્ધ", + "pre_staked": "પ્રી-સ્ટેક્ડ", + "on_blockchain": "બ્લોકચેન પર" + } }, "update_required": { "title": "કૃપા કરીને અપડેટ કરો", diff --git a/src/translations/locales/he.json b/src/translations/locales/he.json index 56e627c2f..dd91313b9 100644 --- a/src/translations/locales/he.json +++ b/src/translations/locales/he.json @@ -555,7 +555,14 @@ "top_miners": "משתמשים מובילים", "top_countries": "מדינות מובילות", "online_miners": "משתמשים מקוונים", - "detailed_information": "מידע מפורט" + "detailed_information": "מידע מפורט", + "total_coins": "סך המטבעות", + "filter": { + "total": "כולם", + "on_app": "זמין באפליקציה", + "pre_staked": "מראש מסומן", + "on_blockchain": "על הבלוקצ'יין" + } }, "update_required": { "title": "נא לעדכן", diff --git a/src/translations/locales/hi.json b/src/translations/locales/hi.json index a2c84333e..c95a20fc9 100644 --- a/src/translations/locales/hi.json +++ b/src/translations/locales/hi.json @@ -555,7 +555,14 @@ "top_miners": "शीर्ष उपयोगकर्ता", "top_countries": "शीर्ष देश", "online_miners": "ऑनलाइन उपयोगकर्ता", - "detailed_information": "विस्तृत जानकारी" + "detailed_information": "विस्तृत जानकारी", + "total_coins": "कुल सिक्के", + "filter": { + "total": "कुल", + "on_app": "ऐप पर उपलब्ध", + "pre_staked": "पूर्व-स्टेक्ड", + "on_blockchain": "ब्लॉकचेन पर" + } }, "update_required": { "title": "कृपया अपडेट करें", diff --git a/src/translations/locales/hu.json b/src/translations/locales/hu.json index 7ca642591..c8ee6a723 100644 --- a/src/translations/locales/hu.json +++ b/src/translations/locales/hu.json @@ -555,7 +555,14 @@ "top_miners": "Top felhasználók", "top_countries": "Top országok", "online_miners": "Online felhasználók", - "detailed_information": "Részletes információ" + "detailed_information": "Részletes információ", + "total_coins": "Összes érme", + "filter": { + "total": "Összesen", + "on_app": "Elérhető az alkalmazásban", + "pre_staked": "Előre lerakott", + "on_blockchain": "A blokkláncban" + } }, "update_required": { "title": "Kérjük, frissítsd", diff --git a/src/translations/locales/id.json b/src/translations/locales/id.json index 57f60201e..f40865981 100644 --- a/src/translations/locales/id.json +++ b/src/translations/locales/id.json @@ -555,7 +555,14 @@ "top_miners": "Pengguna teratas", "top_countries": "Negara teratas", "online_miners": "Pengguna online", - "detailed_information": "Informasi mendetail" + "detailed_information": "Informasi mendetail", + "total_coins": "Total koin", + "filter": { + "total": "Total", + "on_app": "Tersedia di Aplikasi", + "pre_staked": "Pre-Staked", + "on_blockchain": "Di Blockchain" + } }, "update_required": { "title": "Perbarui", diff --git a/src/translations/locales/it.json b/src/translations/locales/it.json index 986518260..738a1880b 100644 --- a/src/translations/locales/it.json +++ b/src/translations/locales/it.json @@ -555,7 +555,14 @@ "top_miners": "Migliori utenti", "top_countries": "Paesi migliori", "online_miners": "Utenti online", - "detailed_information": "Informazioni dettagliate" + "detailed_information": "Informazioni dettagliate", + "total_coins": "Monete totali", + "filter": { + "total": "Totale", + "on_app": "Disponibile sull'app", + "pre_staked": "Pre-Staked", + "on_blockchain": "Sulla blockchain" + } }, "update_required": { "title": "Ti preghiamo di aggiornare", diff --git a/src/translations/locales/ja.json b/src/translations/locales/ja.json index 56217cb88..30e02ffcd 100644 --- a/src/translations/locales/ja.json +++ b/src/translations/locales/ja.json @@ -555,7 +555,14 @@ "top_miners": "トップユーザー", "top_countries": "上位国", "online_miners": "オンラインユーザー", - "detailed_information": "詳細情報" + "detailed_information": "詳細情報", + "total_coins": "総コイン数", + "filter": { + "total": "合計", + "on_app": "アプリで利用可能", + "pre_staked": "事前ステーク", + "on_blockchain": "ブロックチェーン上" + } }, "update_required": { "title": "アップデートしてください", diff --git a/src/translations/locales/jv.json b/src/translations/locales/jv.json index c2831c266..56157f654 100644 --- a/src/translations/locales/jv.json +++ b/src/translations/locales/jv.json @@ -544,7 +544,14 @@ "top_miners": "Top users", "top_countries": "Top countries", "online_miners": "Online users", - "detailed_information": "Detailed information" + "detailed_information": "Detailed information", + "total_coins": "Jumlah Koin", + "filter": { + "total": "Total", + "on_app": "Tersedia di Aplikasi", + "pre_staked": "Pre-Staked", + "on_blockchain": "Di Blockchain" + } }, "update_required": { "title": "Please Update", diff --git a/src/translations/locales/kn.json b/src/translations/locales/kn.json index 6812a5775..ed2d341b2 100644 --- a/src/translations/locales/kn.json +++ b/src/translations/locales/kn.json @@ -555,7 +555,14 @@ "top_miners": "ಟಾಪ್ ಬಳಕೆದಾರರು", "top_countries": "ಟಾಪ್ ದೇಶಗಳು", "online_miners": "ಆನ್ ಲೈನ್ ಬಳಕೆದಾರರು", - "detailed_information": "ವಿವರವಾದ ಮಾಹಿತಿ" + "detailed_information": "ವಿವರವಾದ ಮಾಹಿತಿ", + "total_coins": "ಒಟ್ಟು ನಾಣ್ಯಗಳು", + "filter": { + "total": "ಒಟ್ಟು", + "on_app": "App ಲಲ್ಲಿ ಲಭ್ಯವಿದೆ", + "pre_staked": "ಮೊದಲು ಸ್ಟೇಕ್ ಮಾಡಿದೆ", + "on_blockchain": "ಬ್ಲಾಕ್‌ಚೇನ್‌ನಲ್ಲಿ" + } }, "update_required": { "title": "ದಯವಿಟ್ಟು ನವೀಕರಿಸಿ", diff --git a/src/translations/locales/ko.json b/src/translations/locales/ko.json index ffdc8ce6b..50c1f46c6 100644 --- a/src/translations/locales/ko.json +++ b/src/translations/locales/ko.json @@ -555,7 +555,14 @@ "top_miners": "최고 사용자", "top_countries": "최고 국가", "online_miners": "온라인 사용자", - "detailed_information": "상세 정보" + "detailed_information": "상세 정보", + "total_coins": "총 코인", + "filter": { + "total": "총합", + "on_app": "앱에서 사용 가능", + "pre_staked": "사전 스테이크", + "on_blockchain": "블록체인 상에" + } }, "update_required": { "title": "업데이트하세요", diff --git a/src/translations/locales/mr.json b/src/translations/locales/mr.json index f37b34cd4..87ad3dd26 100644 --- a/src/translations/locales/mr.json +++ b/src/translations/locales/mr.json @@ -555,7 +555,14 @@ "top_miners": "टॉप वापरकर्ते", "top_countries": "टॉप देश", "online_miners": "ऑनलाईन वापरकर्ते", - "detailed_information": "सविस्तर माहिती" + "detailed_information": "सविस्तर माहिती", + "total_coins": "एकूण सिक्के", + "filter": { + "total": "एकूण", + "on_app": "अॅपमध्ये उपलब्ध", + "pre_staked": "मुख्यस्थित", + "on_blockchain": "ब्लॉकचेन वर" + } }, "update_required": { "title": "कृपया अपडेट करा", diff --git a/src/translations/locales/ms.json b/src/translations/locales/ms.json index 9c6f0969a..2bc42da09 100644 --- a/src/translations/locales/ms.json +++ b/src/translations/locales/ms.json @@ -555,7 +555,14 @@ "top_miners": "Pengguna teratas", "top_countries": "Negara teratas", "online_miners": "Pengguna dalam talian", - "detailed_information": "Maklumat terperinci" + "detailed_information": "Maklumat terperinci", + "total_coins": "Jumlah Koin", + "filter": { + "total": "Jumlah Keseluruhan", + "on_app": "Boleh Didapati di Aplikasi", + "pre_staked": "Prastake", + "on_blockchain": "Pada Rantai Blok" + } }, "update_required": { "title": "Sila Kemas Kini", diff --git a/src/translations/locales/nb.json b/src/translations/locales/nb.json index f9d2fc48c..5c1ff6fd1 100644 --- a/src/translations/locales/nb.json +++ b/src/translations/locales/nb.json @@ -555,7 +555,14 @@ "top_miners": "Toppbrukere", "top_countries": "Toppland", "online_miners": "Nettbrukere", - "detailed_information": "Detaljert informasjon" + "detailed_information": "Detaljert informasjon", + "total_coins": "Totalt antall mynter", + "filter": { + "total": "Total", + "on_app": "Tilgjengelig på appen", + "pre_staked": "Forhåndsvalgt", + "on_blockchain": "På blockchainen" + } }, "update_required": { "title": "Vennligst oppdater", diff --git a/src/translations/locales/nn.json b/src/translations/locales/nn.json index 328e9dbf8..f127e4128 100644 --- a/src/translations/locales/nn.json +++ b/src/translations/locales/nn.json @@ -555,7 +555,14 @@ "top_miners": "Toppbrukere", "top_countries": "Toppland", "online_miners": "Nettbrukere", - "detailed_information": "Detaljert informasjon" + "detailed_information": "Detaljert informasjon", + "total_coins": "Totalt antall mynter", + "filter": { + "total": "Totalt", + "on_app": "Tilgjengelig på appen", + "pre_staked": "Forhåndsvalgt", + "on_blockchain": "På blockchainen" + } }, "update_required": { "title": "Vennligst oppdater", diff --git a/src/translations/locales/pa.json b/src/translations/locales/pa.json index 6c10d6212..ed60956e2 100644 --- a/src/translations/locales/pa.json +++ b/src/translations/locales/pa.json @@ -555,7 +555,14 @@ "top_miners": "ਚੋਟੀ ਦੇ ਉਪਭੋਗਤਾ", "top_countries": "ਚੋਟੀ ਦੇ ਦੇਸ਼", "online_miners": "ਔਨਲਾਈਨ ਉਪਭੋਗਤਾ", - "detailed_information": "ਵਿਸਤ੍ਰਿਤ ਜਾਣਕਾਰੀ" + "detailed_information": "ਵਿਸਤ੍ਰਿਤ ਜਾਣਕਾਰੀ", + "total_coins": "ਕੁੱਲ ਸਿੱਕੇ", + "filter": { + "total": "ਕੁੱਲ", + "on_app": "ਐਪ ਉੱਤੇ ਉਪਲਬਧ", + "pre_staked": "ਪੂਰਵ-ਸਟੇਕ", + "on_blockchain": "ਬਲਾਕਚੇਨ ਉੱਤੇ" + } }, "update_required": { "title": "ਕਿਰਪਾ ਕਰਕੇ ਅੱਪਡੇਟ ਕਰੋ", diff --git a/src/translations/locales/pl.json b/src/translations/locales/pl.json index 6db47b88f..e0e7c3665 100644 --- a/src/translations/locales/pl.json +++ b/src/translations/locales/pl.json @@ -555,7 +555,14 @@ "top_miners": "Najlepsi użytkownicy", "top_countries": "Czołowe kraje", "online_miners": "Użytkownicy online", - "detailed_information": "Szczegółowe informacje" + "detailed_information": "Szczegółowe informacje", + "total_coins": "Łączna liczba monet", + "filter": { + "total": "Łącznie", + "on_app": "Dostępne w aplikacji", + "pre_staked": "Pre-staked", + "on_blockchain": "Na blockchainie" + } }, "update_required": { "title": "Prosimy o aktualizację", diff --git a/src/translations/locales/pt.json b/src/translations/locales/pt.json index 8655be2f4..995e09607 100644 --- a/src/translations/locales/pt.json +++ b/src/translations/locales/pt.json @@ -555,7 +555,14 @@ "top_miners": "Principais usuários", "top_countries": "Principais países", "online_miners": "Usuários online", - "detailed_information": "Informações detalhadas" + "detailed_information": "Informações detalhadas", + "total_coins": "Total de moedas", + "filter": { + "total": "Total", + "on_app": "Disponível na aplicação", + "pre_staked": "Pré-Staked", + "on_blockchain": "Na Blockchain" + } }, "update_required": { "title": "Por favor, atualize", diff --git a/src/translations/locales/ro.json b/src/translations/locales/ro.json index 76e28910a..ff506221a 100644 --- a/src/translations/locales/ro.json +++ b/src/translations/locales/ro.json @@ -555,7 +555,14 @@ "top_miners": "Top utilizatori", "top_countries": "Top țări", "online_miners": "Utilizatori online", - "detailed_information": "Informații detaliate" + "detailed_information": "Informații detaliate", + "total_coins": "Total monede", + "filter": { + "total": "Total", + "on_app": "Disponibil în aplicație", + "pre_staked": "Pre-staked", + "on_blockchain": "Blockchain" + } }, "update_required": { "title": "Te rugăm să actualizezi", diff --git a/src/translations/locales/ru.json b/src/translations/locales/ru.json index 9e3860207..487270fb4 100644 --- a/src/translations/locales/ru.json +++ b/src/translations/locales/ru.json @@ -555,7 +555,14 @@ "top_miners": "Ведущие пользователи", "top_countries": "Ведущие страны", "online_miners": "Онлайн-пользователи", - "detailed_information": "Подробная информация" + "detailed_information": "Подробная информация", + "total_coins": "Всего монет", + "filter": { + "total": "Итого", + "on_app": "Доступно в приложении", + "pre_staked": "Предварительный стейк", + "on_blockchain": "На блокчейне" + } }, "update_required": { "title": "Пожалуйста, обновите", diff --git a/src/translations/locales/sk.json b/src/translations/locales/sk.json index 1cb5fbe62..3773ad83c 100644 --- a/src/translations/locales/sk.json +++ b/src/translations/locales/sk.json @@ -555,7 +555,14 @@ "top_miners": "Top používatelia", "top_countries": "Top krajiny", "online_miners": "Online používatelia", - "detailed_information": "Podrobné informácie" + "detailed_information": "Podrobné informácie", + "total_coins": "Celkový počet mincí", + "filter": { + "total": "Celkovo", + "on_app": "Dostupné v aplikácii", + "pre_staked": "Predstavené", + "on_blockchain": "Na blockchaine" + } }, "update_required": { "title": "Prosím, aktualizuj", diff --git a/src/translations/locales/sl.json b/src/translations/locales/sl.json index 12c9d4275..051d3e6ef 100644 --- a/src/translations/locales/sl.json +++ b/src/translations/locales/sl.json @@ -555,7 +555,14 @@ "top_miners": "Najboljši uporabniki", "top_countries": "Najboljše države", "online_miners": "Spletni uporabniki", - "detailed_information": "Podrobne informacije" + "detailed_information": "Podrobne informacije", + "total_coins": "Skupno kovancev", + "filter": { + "total": "Skupaj", + "on_app": "Na voljo v aplikaciji", + "pre_staked": "Pred stavko", + "on_blockchain": "Na verigi blokov" + } }, "update_required": { "title": "Prosimo, posodobite", diff --git a/src/translations/locales/sq.json b/src/translations/locales/sq.json index a6bd2053d..d223f218a 100644 --- a/src/translations/locales/sq.json +++ b/src/translations/locales/sq.json @@ -555,7 +555,14 @@ "top_miners": "Përdoruesit kryesorë", "top_countries": "Vendet kryesore", "online_miners": "Përdoruesit në internet", - "detailed_information": "Informacion i detajuar" + "detailed_information": "Informacion i detajuar", + "total_coins": "Totali i monedhëve", + "filter": { + "total": "Totali", + "on_app": "I disponueshëm në aplikacion", + "pre_staked": "Përpara staked", + "on_blockchain": "Në blockchain" + } }, "update_required": { "title": "Të lutemi përditëso", diff --git a/src/translations/locales/sv.json b/src/translations/locales/sv.json index d0aa402bb..308708fdc 100644 --- a/src/translations/locales/sv.json +++ b/src/translations/locales/sv.json @@ -555,7 +555,14 @@ "top_miners": "Toppanvändare", "top_countries": "Toppländer", "online_miners": "Onlineanvändare", - "detailed_information": "Detaljerad information" + "detailed_information": "Detaljerad information", + "total_coins": "Totalt antal mynt", + "filter": { + "total": "Totalt", + "on_app": "Tillgängligt i appen", + "pre_staked": "Förinställt", + "on_blockchain": "På blockkedjan" + } }, "update_required": { "title": "Vänligen uppdatera", diff --git a/src/translations/locales/te.json b/src/translations/locales/te.json index 17ff811cd..dbdbee42a 100644 --- a/src/translations/locales/te.json +++ b/src/translations/locales/te.json @@ -555,7 +555,14 @@ "top_miners": "టాప్ యూజర్​లు", "top_countries": "టాప్ దేశాలు", "online_miners": "ఆన్​లైన్ యూజర్​లు", - "detailed_information": "సవిస్తరమైన సమాచారం" + "detailed_information": "సవిస్తరమైన సమాచారం", + "total_coins": "మొత్తం కాయినులు", + "filter": { + "total": "మొత్తం", + "on_app": "అప్లికేషన్‌లో అందుబాటులో", + "pre_staked": "ప్రీ-స్టేక్‌డ్", + "on_blockchain": "బ్లాక్‌చైన్‌లో" + } }, "update_required": { "title": "దయచేసి అప్​డేట్ చేయండి", diff --git a/src/translations/locales/th.json b/src/translations/locales/th.json index 64b8b5837..d2b1e4e9b 100644 --- a/src/translations/locales/th.json +++ b/src/translations/locales/th.json @@ -556,7 +556,14 @@ "top_miners": "ผู้ใช้อันดับต้น", "top_countries": "ประเทศอันดับต้น", "online_miners": "ผู้ใช้ทางออนไลน์", - "detailed_information": "ข้อมูลอย่างละเอียด" + "detailed_information": "ข้อมูลอย่างละเอียด", + "total_coins": "จำนวนเหรียญทั้งหมด", + "filter": { + "total": "รวม", + "on_app": "มีในแอป", + "pre_staked": "ก่อนเข็มกลาด", + "on_blockchain": "บนบล็อกเชน" + } }, "update_required": { "title": "โปรดอัปเดต", diff --git a/src/translations/locales/tr.json b/src/translations/locales/tr.json index fc75fa68c..92501e20b 100644 --- a/src/translations/locales/tr.json +++ b/src/translations/locales/tr.json @@ -555,7 +555,14 @@ "top_miners": "En popüler kullanıcılar", "top_countries": "En popüler ülkeler", "online_miners": "Çevrimiçi kullanıcılar", - "detailed_information": "Detaylı bilgi" + "detailed_information": "Detaylı bilgi", + "total_coins": "Toplam Madeni Para", + "filter": { + "total": "Toplam", + "on_app": "Uygulamada Mevcut", + "pre_staked": "Önceden Stake Edilen", + "on_blockchain": "Blockchain Üzerinde" + } }, "update_required": { "title": "Lütfen Güncelle", diff --git a/src/translations/locales/uk.json b/src/translations/locales/uk.json index 3d1fc04db..a6b5e3796 100644 --- a/src/translations/locales/uk.json +++ b/src/translations/locales/uk.json @@ -555,7 +555,14 @@ "top_miners": "Топ користувачів", "top_countries": "Найпопулярніші країни", "online_miners": "Онлайн-користувачі", - "detailed_information": "Детальна інформація" + "detailed_information": "Детальна інформація", + "total_coins": "Загальна кількість монет", + "filter": { + "total": "Загальна", + "on_app": "Доступно в додатку", + "pre_staked": "Попередній стейк", + "on_blockchain": "На блокчейні" + } }, "update_required": { "title": "Будь ласка, оновіть", diff --git a/src/translations/locales/ur.json b/src/translations/locales/ur.json index 9db7ad900..3320b48ed 100644 --- a/src/translations/locales/ur.json +++ b/src/translations/locales/ur.json @@ -555,7 +555,14 @@ "top_miners": "سر فہرست صارفین", "top_countries": "سر فہرست ممالک", "online_miners": "آن لائن صارفین", - "detailed_information": "تفصیلی معلومات" + "detailed_information": "تفصیلی معلومات", + "total_coins": "کل سکے", + "filter": { + "total": "کل", + "on_app": "ایپلیکیشن میں دستیاب ہے", + "pre_staked": "پیش سٹیک", + "on_blockchain": "بلاک چین پر" + } }, "update_required": { "title": "براہ کرم اپڈیٹ کریں", diff --git a/src/translations/locales/vi.json b/src/translations/locales/vi.json index 9c5e2d54d..3bda088ae 100644 --- a/src/translations/locales/vi.json +++ b/src/translations/locales/vi.json @@ -555,7 +555,14 @@ "top_miners": "Người dùng hàng đầu", "top_countries": "Các quốc gia hàng đầu", "online_miners": "Người dùng trực tuyến", - "detailed_information": "Thông tin chi tiết" + "detailed_information": "Thông tin chi tiết", + "total_coins": "Tổng số đồng tiền", + "filter": { + "total": "Tổng", + "on_app": "Có sẵn trên ứng dụng", + "pre_staked": "Trước khi gắn cờ", + "on_blockchain": "Trên Blockchain" + } }, "update_required": { "title": "Vui lòng cập nhật", diff --git a/src/translations/locales/zh-hant.json b/src/translations/locales/zh-hant.json index 3bf3cb073..984a73394 100644 --- a/src/translations/locales/zh-hant.json +++ b/src/translations/locales/zh-hant.json @@ -555,7 +555,14 @@ "top_miners": "使用者排名", "top_countries": "國家排名", "online_miners": "線上使用者", - "detailed_information": "詳細資訊" + "detailed_information": "詳細資訊", + "total_coins": "總硬幣數量", + "filter": { + "total": "總量", + "on_app": "在應用程式上可用", + "pre_staked": "預先抵押", + "on_blockchain": "在區塊鏈上" + } }, "update_required": { "title": "請進行更新", diff --git a/src/translations/locales/zh.json b/src/translations/locales/zh.json index a5e63861b..5dee8db67 100644 --- a/src/translations/locales/zh.json +++ b/src/translations/locales/zh.json @@ -555,7 +555,14 @@ "top_miners": "热门用户", "top_countries": "热门国家/地区", "online_miners": "在线用户", - "detailed_information": "详细信息" + "detailed_information": "详细信息", + "total_coins": "总硬币数量", + "filter": { + "total": "总量", + "on_app": "在应用上可用", + "pre_staked": "预先抵押", + "on_blockchain": "在区块链上" + } }, "update_required": { "title": "请更新",