From f4b84715348d3041de1dc8466c397dc8a79911e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 16 Oct 2023 16:18:10 +0200 Subject: [PATCH 01/11] Refactor `island` redux selectors --- src/redux-state/selectors.ts | 16 +++++ src/redux-state/selectors/island.ts | 107 +++++++++++++++------------- src/redux-state/slices/island.ts | 2 +- 3 files changed, 74 insertions(+), 51 deletions(-) create mode 100644 src/redux-state/selectors.ts diff --git a/src/redux-state/selectors.ts b/src/redux-state/selectors.ts new file mode 100644 index 000000000..e7e104eec --- /dev/null +++ b/src/redux-state/selectors.ts @@ -0,0 +1,16 @@ +import { createSelector } from "@reduxjs/toolkit" +import { IslandState } from "redux-state/slices/island" +import { RootState } from "./reducers" + +export type IslandSelector = ( + state: RootState +) => IslandState[K] + +export type CreateIslandSelector = ( + value: K +) => IslandSelector + +export const selectIsland = (state: RootState) => state.island + +export const createIslandSelector: CreateIslandSelector = (value) => + createSelector(selectIsland, (island) => island[value]) diff --git a/src/redux-state/selectors/island.ts b/src/redux-state/selectors/island.ts index 22ccb92b1..ff4117e14 100644 --- a/src/redux-state/selectors/island.ts +++ b/src/redux-state/selectors/island.ts @@ -1,20 +1,45 @@ import { createSelector } from "@reduxjs/toolkit" -import { RootState } from "redux-state/reducers" import { DAY } from "shared/constants" import { isSameAddress } from "shared/utils" +import { createIslandSelector } from "redux-state/selectors" +import { IslandModeType } from "redux-state/slices/island" +import { RealmData, SeasonInfo } from "shared/types" +import { RootState } from "redux-state/reducers" -export const selectIslandMode = (state: RootState) => state.island.mode - -export const selectIsDefaultIslandMode = (state: RootState) => - state.island.mode === "default" - -export const selectIsJoinRealmIslandMode = (state: RootState) => - state.island.mode === "join-realm" - -export const selectIslandOverlay = (state: RootState) => state.island.overlay - -export const selectRealms = (state: RootState) => state.island.realms - +type SeasonInfoProperty = ( + value: K +) => (state: RootState) => SeasonInfo[K] | undefined + +type DisplayedRealmProperty = ( + value: K +) => (state: RootState) => RealmData[K] | undefined + +/* Base selectors */ +export const selectIslandMode = createIslandSelector("mode") +export const selectIslandOverlay = createIslandSelector("overlay") +export const selectIslandZoomLevel = createIslandSelector("zoomLevel") +export const selectRealms = createIslandSelector("realms") +export const selectSeasonInfo = createIslandSelector("seasonInfo") +export const selectDisplayedRealmId = createIslandSelector("displayedRealmId") +export const selectLeaderboards = createIslandSelector("leaderboards") +export const selectUnclaimedXp = createIslandSelector("unclaimedXp") +export const selectStakeUnlockTime = createIslandSelector("stakeUnlockTime") +export const selectStakingRealmId = createIslandSelector("stakingRealmId") + +/* Helpers */ +const checkIslandMode = (value: IslandModeType) => + createSelector(selectIslandMode, (mode) => mode === value) + +const selectSeasonInfoProperty: SeasonInfoProperty = (value) => + createSelector(selectSeasonInfo, (seasonInfo) => + seasonInfo ? seasonInfo[value] : undefined + ) + +/* Island info - selectors */ +export const selectIsDefaultIslandMode = checkIslandMode("default") +export const selectIsJoinRealmIslandMode = checkIslandMode("join-realm") + +/* Realms info - selectors */ export const selectRealmById = createSelector( [selectRealms, (_, realmId: string | null) => realmId], (realms, realmId) => (realmId ? realms[realmId] : null) @@ -29,23 +54,20 @@ export const selectRealmWithIdByAddress = createSelector( ) /* Season info - selectors */ -export const selectSeasonStartTimestamp = (state: RootState) => - state.island.seasonInfo?.seasonStartTimestamp +export const selectSeasonStartTimestamp = selectSeasonInfoProperty( + "seasonStartTimestamp" +) -export const selectSeasonEndTimestamp = (state: RootState) => - state.island.seasonInfo?.seasonEndTimestamp +export const selectSeasonEndTimestamp = + selectSeasonInfoProperty("seasonEndTimestamp") -export const selectSeasonDurationInWeeks = (state: RootState) => - state.island.seasonInfo?.durationInWeeks +export const selectSeasonDurationInWeeks = + selectSeasonInfoProperty("durationInWeeks") export const selectIsEndOfSeason = createSelector( selectSeasonEndTimestamp, - (seasonEndTimestamp) => { - if (seasonEndTimestamp) { - return Date.now() > seasonEndTimestamp - } - return null - } + (seasonEndTimestamp) => + seasonEndTimestamp ? Date.now() > seasonEndTimestamp : null ) export const selectSeasonWeek = createSelector( @@ -88,25 +110,20 @@ export const selectWeekEndDate = createSelector( ) /* Displayed Realm - selectors */ -export const selectDisplayedRealmId = (state: RootState) => - state.island.displayedRealmId +const selectDisplayedRealmProperty: DisplayedRealmProperty = (value) => + createSelector(selectRealms, selectDisplayedRealmId, (realms, realmId) => + realmId && realms[realmId] ? realms[realmId][value] : undefined + ) -export const selectDisplayedRealmAddress = createSelector( - selectRealms, - selectDisplayedRealmId, - (realms, realmId) => realmId && realms[realmId]?.realmContractAddress +export const selectDisplayedRealmAddress = selectDisplayedRealmProperty( + "realmContractAddress" ) -export const selectDisplayedRealmVeTokenAddress = createSelector( - selectRealms, - selectDisplayedRealmId, - (realms, realmId) => realmId && realms[realmId]?.veTokenContractAddress +export const selectDisplayedRealmVeTokenAddress = selectDisplayedRealmProperty( + "veTokenContractAddress" ) /* Staking Realm - selectors */ -export const selectStakingRealmId = (state: RootState) => - state.island.stakingRealmId - export const selectStakingRealmAddress = createSelector( selectRealms, selectStakingRealmId, @@ -114,12 +131,7 @@ export const selectStakingRealmAddress = createSelector( stakingRealmId && realms[stakingRealmId]?.realmContractAddress ) -/* Xp selectors */ -export const selectLeaderboards = (state: RootState) => - state.island.leaderboards - -export const selectUnclaimedXp = (state: RootState) => state.island.unclaimedXp - +/* Leaderboard selectors */ const selectLeaderboardDataById = createSelector( [(_, realmId: string) => realmId, selectLeaderboards], (realmId, leaderboards) => leaderboards[realmId] @@ -135,6 +147,7 @@ export const selectUserLeaderboardRankById = createSelector( (leaderboardData) => leaderboardData?.currentUser ?? null ) +/* Xp selectors */ export const selectUnclaimedXpById = createSelector( [(_, realmId: string) => realmId, selectUnclaimedXp], (realmId, unclaimedXp) => unclaimedXp[realmId] @@ -188,9 +201,3 @@ export const selectIsStakingRealmDisplayed = createSelector( !!displayedAddress && isSameAddress(stakingAddress, displayedAddress) ) - -export const selectStakeUnlockTime = (state: RootState) => - state.island.stakeUnlockTime - -export const selectIslandZoomLevel = (state: RootState) => - state.island.zoomLevel diff --git a/src/redux-state/slices/island.ts b/src/redux-state/slices/island.ts index 77f4a7b1d..9cc48a802 100644 --- a/src/redux-state/slices/island.ts +++ b/src/redux-state/slices/island.ts @@ -8,7 +8,7 @@ import { SeasonInfo, } from "shared/types" -type IslandModeType = "default" | "join-realm" +export type IslandModeType = "default" | "join-realm" export type IslandState = { mode: IslandModeType From edd42eadb9b56cddbc4b09ad9b0c49e2feedd6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 16 Oct 2023 17:18:41 +0200 Subject: [PATCH 02/11] Refactor `claim` selectors --- src/redux-state/selectors.ts | 17 +++++++++++-- src/redux-state/selectors/claim.ts | 38 ++++++++++++++++++------------ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/redux-state/selectors.ts b/src/redux-state/selectors.ts index e7e104eec..1007a4057 100644 --- a/src/redux-state/selectors.ts +++ b/src/redux-state/selectors.ts @@ -1,16 +1,29 @@ import { createSelector } from "@reduxjs/toolkit" import { IslandState } from "redux-state/slices/island" +import { ClaimState } from "./slices/claim" import { RootState } from "./reducers" -export type IslandSelector = ( +type IslandSelector = ( state: RootState ) => IslandState[K] -export type CreateIslandSelector = ( +type ClaimSelector = ( + state: RootState +) => ClaimState[K] + +type CreateIslandSelector = ( value: K ) => IslandSelector +type CreateClaimSelector = ( + value: K +) => ClaimSelector + export const selectIsland = (state: RootState) => state.island +export const selectClaim = (state: RootState) => state.claim export const createIslandSelector: CreateIslandSelector = (value) => createSelector(selectIsland, (island) => island[value]) + +export const createClaimSelector: CreateClaimSelector = (value) => + createSelector(selectClaim, (claim) => claim[value]) diff --git a/src/redux-state/selectors/claim.ts b/src/redux-state/selectors/claim.ts index f9dfe9b28..1d3a47103 100644 --- a/src/redux-state/selectors/claim.ts +++ b/src/redux-state/selectors/claim.ts @@ -2,30 +2,38 @@ import { createSelector } from "@reduxjs/toolkit" import { RootState } from "redux-state/reducers" import { truncateAddress } from "shared/utils" import { RealmData } from "shared/types" +import { createClaimSelector } from "redux-state/selectors" import { selectRealmById } from "./island" -export const selectClaimingUser = (state: RootState) => ({ - name: state.claim.name || truncateAddress(state.claim.address), - address: state.claim.address, -}) +/* Base selectors */ +export const selectHasClaimed = createClaimSelector("hasClaimed") +export const selectEligibility = createClaimSelector("eligibility") +export const selectRealmId = createClaimSelector("selectedRealmId") +export const selectClaimingStakeAmount = createClaimSelector("stakeAmount") +export const selectClaimAdress = createClaimSelector("address") +export const selectClaimName = createClaimSelector("name") -export const selectHasClaimed = (state: RootState) => state.claim.hasClaimed +export const selectUseConnectedWalletToClaim = + createClaimSelector("useConnectedWallet") + +export const selectRepresentativeAddress = createClaimSelector( + "representativeAddress" +) -export const selectEligibility = (state: RootState) => state.claim.eligibility +export const selectClaimingSelectedRealmId = + createClaimSelector("selectedRealmId") -export const selectUseConnectedWalletToClaim = (state: RootState) => - state.claim.useConnectedWallet +export const selectClaimingUser = (state: RootState) => ({ + name: selectClaimName(state) || truncateAddress(selectClaimAdress(state)), + address: selectClaimAdress(state), +}) export const selectStakingData = createSelector( - (state: RootState) => selectRealmById(state, state.claim.selectedRealmId), - (state: RootState) => state.claim.stakeAmount, + (state: RootState) => + selectRealmById(state, selectClaimingSelectedRealmId(state)), + (state: RootState) => selectClaimingStakeAmount(state), (realmData: RealmData | null, stakeAmount) => ({ realmContractAddress: realmData ? realmData.realmContractAddress : null, stakeAmount, }) ) - -export const selectRepresentativeAddress = (state: RootState) => - state.claim.representativeAddress - -export const selectRealmId = (state: RootState) => state.claim.selectedRealmId From cc5530e2b76f5fd95c8adf26ea528704f73e2f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 16 Oct 2023 17:30:08 +0200 Subject: [PATCH 03/11] Refactor `wallet` selectors --- src/redux-state/selectors.ts | 13 +++++++++++++ src/redux-state/selectors/wallet.ts | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/redux-state/selectors.ts b/src/redux-state/selectors.ts index 1007a4057..6eafa749c 100644 --- a/src/redux-state/selectors.ts +++ b/src/redux-state/selectors.ts @@ -2,6 +2,7 @@ import { createSelector } from "@reduxjs/toolkit" import { IslandState } from "redux-state/slices/island" import { ClaimState } from "./slices/claim" import { RootState } from "./reducers" +import { WalletState } from "./slices/wallet" type IslandSelector = ( state: RootState @@ -11,6 +12,10 @@ type ClaimSelector = ( state: RootState ) => ClaimState[K] +type WalletSelector = ( + state: RootState +) => WalletState[K] + type CreateIslandSelector = ( value: K ) => IslandSelector @@ -19,11 +24,19 @@ type CreateClaimSelector = ( value: K ) => ClaimSelector +type CreateWalletSelector = ( + value: K +) => WalletSelector + export const selectIsland = (state: RootState) => state.island export const selectClaim = (state: RootState) => state.claim +export const selectWallet = (state: RootState) => state.wallet export const createIslandSelector: CreateIslandSelector = (value) => createSelector(selectIsland, (island) => island[value]) export const createClaimSelector: CreateClaimSelector = (value) => createSelector(selectClaim, (claim) => claim[value]) + +export const createWalletSelector: CreateWalletSelector = (value) => + createSelector(selectWallet, (wallet) => wallet[value]) diff --git a/src/redux-state/selectors/wallet.ts b/src/redux-state/selectors/wallet.ts index 71d4c3432..1eadc6784 100644 --- a/src/redux-state/selectors/wallet.ts +++ b/src/redux-state/selectors/wallet.ts @@ -2,21 +2,21 @@ import { createSelector } from "@reduxjs/toolkit" import { RootState } from "redux-state/reducers" import { TransactionProgressStatus } from "shared/types" import { truncateAddress } from "shared/utils" +import { createWalletSelector } from "redux-state/selectors" -export const selectWalletAddress = (state: RootState) => state.wallet.address +/* Base selectors */ + +export const selectWalletAddress = createWalletSelector("address") +export const selectWalletAvatar = createWalletSelector("avatar") +export const selectWalletNameProperty = createWalletSelector("name") +export const selectIsWalletConnected = createWalletSelector("isConnected") +export const selectTokenBalances = createWalletSelector("balances") export const selectWalletTruncatedAddress = (state: RootState) => - truncateAddress(state.wallet.address) + truncateAddress(selectWalletAddress(state)) export const selectWalletName = (state: RootState) => - state.wallet.name || truncateAddress(state.wallet.address) - -export const selectWalletAvatar = (state: RootState) => state.wallet.avatar - -export const selectIsWalletConnected = (state: RootState) => - state.wallet.isConnected - -export const selectTokenBalances = (state: RootState) => state.wallet.balances + selectWalletNameProperty(state) || truncateAddress(selectWalletAddress(state)) export const selectTokenBalanceByAddress = createSelector( [selectTokenBalances, (_, tokenAddress) => tokenAddress], From 6da1659c13b6f7aa7000786f1be09da6d4104be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 16 Oct 2023 17:58:11 +0200 Subject: [PATCH 04/11] Create file for selector types --- src/redux-state/selectors.ts | 32 +++++--------------------------- src/shared/types/selectors.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 src/shared/types/selectors.ts diff --git a/src/redux-state/selectors.ts b/src/redux-state/selectors.ts index 6eafa749c..1cf798c2a 100644 --- a/src/redux-state/selectors.ts +++ b/src/redux-state/selectors.ts @@ -1,32 +1,10 @@ import { createSelector } from "@reduxjs/toolkit" -import { IslandState } from "redux-state/slices/island" -import { ClaimState } from "./slices/claim" +import { + CreateIslandSelector, + CreateClaimSelector, + CreateWalletSelector, +} from "shared/types/selectors" import { RootState } from "./reducers" -import { WalletState } from "./slices/wallet" - -type IslandSelector = ( - state: RootState -) => IslandState[K] - -type ClaimSelector = ( - state: RootState -) => ClaimState[K] - -type WalletSelector = ( - state: RootState -) => WalletState[K] - -type CreateIslandSelector = ( - value: K -) => IslandSelector - -type CreateClaimSelector = ( - value: K -) => ClaimSelector - -type CreateWalletSelector = ( - value: K -) => WalletSelector export const selectIsland = (state: RootState) => state.island export const selectClaim = (state: RootState) => state.claim diff --git a/src/shared/types/selectors.ts b/src/shared/types/selectors.ts new file mode 100644 index 000000000..71ba4b1f6 --- /dev/null +++ b/src/shared/types/selectors.ts @@ -0,0 +1,28 @@ +import { IslandState } from "redux-state/slices/island" +import { ClaimState } from "redux-state/slices/claim" +import { WalletState } from "redux-state/slices/wallet" +import { RootState } from "redux-state/reducers" + +type IslandSelector = ( + state: RootState +) => IslandState[K] + +type ClaimSelector = ( + state: RootState +) => ClaimState[K] + +type WalletSelector = ( + state: RootState +) => WalletState[K] + +export type CreateIslandSelector = ( + value: K +) => IslandSelector + +export type CreateClaimSelector = ( + value: K +) => ClaimSelector + +export type CreateWalletSelector = ( + value: K +) => WalletSelector From bef0d04edb335f2a0e6117305b59ba5d6c6ffb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Tue, 17 Oct 2023 10:53:44 +0200 Subject: [PATCH 05/11] Selector types refactor --- src/shared/types/selectors.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/shared/types/selectors.ts b/src/shared/types/selectors.ts index 71ba4b1f6..e914a93b5 100644 --- a/src/shared/types/selectors.ts +++ b/src/shared/types/selectors.ts @@ -3,17 +3,11 @@ import { ClaimState } from "redux-state/slices/claim" import { WalletState } from "redux-state/slices/wallet" import { RootState } from "redux-state/reducers" -type IslandSelector = ( - state: RootState -) => IslandState[K] +type Selector = (state: RootState) => T[K] -type ClaimSelector = ( - state: RootState -) => ClaimState[K] - -type WalletSelector = ( - state: RootState -) => WalletState[K] +type IslandSelector = Selector +type ClaimSelector = Selector +type WalletSelector = Selector export type CreateIslandSelector = ( value: K From 32a66a476d5446e2dc13d5b6dd579e50471ea9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Tue, 24 Oct 2023 08:54:24 +0200 Subject: [PATCH 06/11] Further refactoring --- src/redux-state/selectors/claim.ts | 5 ++--- src/redux-state/selectors/island.ts | 27 +++++++++++++-------------- src/redux-state/selectors/wallet.ts | 14 ++++++++------ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/redux-state/selectors/claim.ts b/src/redux-state/selectors/claim.ts index 1d3a47103..e8bfd2ec4 100644 --- a/src/redux-state/selectors/claim.ts +++ b/src/redux-state/selectors/claim.ts @@ -12,22 +12,21 @@ export const selectRealmId = createClaimSelector("selectedRealmId") export const selectClaimingStakeAmount = createClaimSelector("stakeAmount") export const selectClaimAdress = createClaimSelector("address") export const selectClaimName = createClaimSelector("name") - export const selectUseConnectedWalletToClaim = createClaimSelector("useConnectedWallet") - export const selectRepresentativeAddress = createClaimSelector( "representativeAddress" ) - export const selectClaimingSelectedRealmId = createClaimSelector("selectedRealmId") +/* User selectors */ export const selectClaimingUser = (state: RootState) => ({ name: selectClaimName(state) || truncateAddress(selectClaimAdress(state)), address: selectClaimAdress(state), }) +/* Staking selectors */ export const selectStakingData = createSelector( (state: RootState) => selectRealmById(state, selectClaimingSelectedRealmId(state)), diff --git a/src/redux-state/selectors/island.ts b/src/redux-state/selectors/island.ts index dc7592431..eb77ed89c 100644 --- a/src/redux-state/selectors/island.ts +++ b/src/redux-state/selectors/island.ts @@ -35,6 +35,14 @@ const selectSeasonInfoProperty: SeasonInfoProperty = (value) => seasonInfo ? seasonInfo[value] : undefined ) +const selectDisplayedRealmProperty: DisplayedRealmProperty = (value) => + createSelector(selectRealms, selectDisplayedRealmId, (realms, realmId) => + realmId && realms[realmId] ? realms[realmId][value] : undefined + ) + +const getPopulationOfRealms = (realms: RealmData[]) => + realms.map((realm) => realm.population) + /* Island info - selectors */ export const selectIsDefaultIslandMode = checkIslandMode("default") export const selectIsJoinRealmIslandMode = checkIslandMode("join-realm") @@ -59,7 +67,7 @@ export const selectHasLoadedRealmData = createSelector( ) export const selectHasLoadedSeasonInfo = createSelector( - (state: RootState) => state.island.seasonInfo, + selectSeasonInfo, (seasonInfo) => seasonInfo !== null ) @@ -120,11 +128,6 @@ export const selectWeekEndDate = createSelector( ) /* Displayed Realm - selectors */ -const selectDisplayedRealmProperty: DisplayedRealmProperty = (value) => - createSelector(selectRealms, selectDisplayedRealmId, (realms, realmId) => - realmId && realms[realmId] ? realms[realmId][value] : undefined - ) - export const selectDisplayedRealmAddress = selectDisplayedRealmProperty( "realmContractAddress" ) @@ -171,15 +174,14 @@ export const selectUnclaimedXpSumById = createSelector( 0 ) ?? 0 ) -/* Population - selectors */ +/* Population selectors */ export const selectSortedPopulation = createSelector(selectRealms, (realms) => { const realmsData = Object.entries(realms).map(([id, data]) => ({ id, ...data, })) - const sortedRealms = realmsData.sort((a, b) => a.population - b.population) - return sortedRealms + return realmsData.sort((a, b) => a.population - b.population) }) export const selectPopulationById = createSelector( @@ -190,15 +192,12 @@ export const selectPopulationById = createSelector( export const selectTotalPopulation = createSelector( selectSortedPopulation, (realms) => - realms.length - ? realms.map((realm) => realm.population).reduce((a, b) => a + b) - : 0 + realms.length ? getPopulationOfRealms(realms).reduce((a, b) => a + b) : 0 ) export const selectMaxPopulation = createSelector( selectSortedPopulation, - (realms) => - realms.length ? Math.max(...realms.map((realm) => realm.population)) : 0 + (realms) => (realms.length ? Math.max(...getPopulationOfRealms(realms)) : 0) ) /* Helpful selectors */ diff --git a/src/redux-state/selectors/wallet.ts b/src/redux-state/selectors/wallet.ts index d48d12349..57ec89995 100644 --- a/src/redux-state/selectors/wallet.ts +++ b/src/redux-state/selectors/wallet.ts @@ -6,22 +6,23 @@ import { truncateAddress } from "shared/utils" import { createWalletSelector } from "redux-state/selectors" /* Base selectors */ - export const selectWalletAddress = createWalletSelector("address") export const selectWalletAvatar = createWalletSelector("avatar") export const selectWalletNameProperty = createWalletSelector("name") export const selectIsWalletConnected = createWalletSelector("isConnected") export const selectTokenBalances = createWalletSelector("balances") +export const selectHasLoadedBalances = createWalletSelector("hasLoadedBalances") +export const selectWalletTransactionStatus = + createWalletSelector("transactionStatus") +/* Wallet identification selectors */ export const selectWalletTruncatedAddress = (state: RootState) => truncateAddress(selectWalletAddress(state)) export const selectWalletName = (state: RootState) => - selectWalletNameProperty(state) || truncateAddress(selectWalletAddress(state)) - -export const selectHasLoadedBalances = (state: RootState) => - state.wallet.hasLoadedBalances + selectWalletNameProperty(state) || selectWalletTruncatedAddress(state) +/* Token selectors */ export const selectTokenBalanceByAddress = createSelector( [selectTokenBalances, (_, tokenAddress) => tokenAddress], (balances, tokenAddress) => balances[tokenAddress]?.balance ?? 0n @@ -56,8 +57,9 @@ export const selectHasRelevantTokens = createSelector( }) ) +/* Transaction selectors */ export const selectTransactionStatusById = createSelector( - [(_, id: string) => id, (state: RootState) => state.wallet.transactionStatus], + [(_, id: string) => id, selectWalletTransactionStatus], (id, transactionStatus) => transactionStatus[id] ?? TransactionProgressStatus.Idle ) From da13cbae5d48f5188c8c2b40683d9e244f6e8b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Thu, 26 Oct 2023 15:31:40 +0200 Subject: [PATCH 07/11] Fix wallet data destructuring --- src/redux-state/thunks/wallet.ts | 12 +++---- src/shared/utils/names.ts | 16 +++++----- src/shared/utils/uns.ts | 32 +++++++++++-------- .../LeaderboardList/LeaderboardItem.tsx | 10 +++--- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/redux-state/thunks/wallet.ts b/src/redux-state/thunks/wallet.ts index 56b2ec950..ffce0570c 100644 --- a/src/redux-state/thunks/wallet.ts +++ b/src/redux-state/thunks/wallet.ts @@ -24,23 +24,23 @@ export const fetchWalletName = createDappAsyncThunk( claim: { useConnectedWallet }, } = getState() - const { name, avatar } = await resolveAddressToWalletData(address) + const data = await resolveAddressToWalletData(address) - if (name) { + if (data) { dispatch( updateConnectedWallet({ address, - name, - avatar, + ...(data.name ? { name: data.name } : {}), + ...(data.avatar ? { name: data.avatar } : {}), }) ) if (useConnectedWallet) { - dispatch(setClaimingUser({ name, address })) + dispatch(setClaimingUser({ name: data.name, address })) } } - return name + return data?.name } ) diff --git a/src/shared/utils/names.ts b/src/shared/utils/names.ts index ec21305d3..5af5a1931 100644 --- a/src/shared/utils/names.ts +++ b/src/shared/utils/names.ts @@ -52,9 +52,11 @@ const resolveENSPromise = (address: string) => }) const resolveUNSPromise = (address: string) => - resolveAddressToUNS(address).then((name): string => { + resolveAddressToUNS(address).then((name): WalletData | null => { + if (!name) return null + addCachedName({ type: "uns", address, name }) - return name + return { name } }) const resolveUnknownNamePromise = () => @@ -75,12 +77,12 @@ const resolveAddressToWalletDataWithoutCache = async (address: string) => { const { name, avatar } = await resolveAddressPromiseCache[normalizedAddress] - return { name, avatar } + return name ? { name, avatar } : null } export const resolveAddressToWalletData = async ( address: string -): Promise => { +): Promise => { const cachedNames = getCachedNames() const normalizedAddress = normalizeAddress(address) @@ -90,11 +92,9 @@ export const resolveAddressToWalletData = async ( return cachedItem.ens ?? cachedItem.uns } - const { name, avatar } = await resolveAddressToWalletDataWithoutCache( - normalizedAddress - ) + const data = await resolveAddressToWalletDataWithoutCache(normalizedAddress) - return { name, avatar } + return data ? { name: data.name, avatar: data.avatar } : null } export const resolveNameToAddress = async (addressOrName: string) => { diff --git a/src/shared/utils/uns.ts b/src/shared/utils/uns.ts index de4a6046f..95fb35800 100644 --- a/src/shared/utils/uns.ts +++ b/src/shared/utils/uns.ts @@ -50,23 +50,27 @@ export const resolveUNS = async (name: string) => { } export const resolveAddressToUNS = async (address: string) => { - const response: UNSReverseResponse = await fetchJson({ - url: `https://resolve.unstoppabledomains.com/domains/?owners=${address}&sortBy=id&sortDirection=ASC`, - headers: { - Authorization: `Bearer ${process.env.UNS_API_KEY}`, - }, - }) + try { + const response: UNSReverseResponse = await fetchJson({ + url: `https://resolve.unstoppabledomains.com/domains/?owners=${address}&sortBy=id&sortDirection=ASC`, + headers: { + Authorization: `Bearer ${process.env.UNS_API_KEY}`, + }, + }) - const { data }: UNSReverseResponse = response + const { data }: UNSReverseResponse = response - const name = data[0]?.id ?? null + const name = data[0]?.id ?? null - if (!name) { - throw new Error("Invalid UNS domain name") - } + if (!name) { + throw new Error("Invalid UNS domain name") + } - // FIXME: UNS tend to resolve faster than ENS, so to prefer ENS names let's wait a bit - await wait(10000) + // FIXME: UNS tend to resolve faster than ENS, so to prefer ENS names let's wait a bit + await wait(10000) - return name + return name + } catch { + return null + } } diff --git a/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx b/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx index 84af5c072..d2aadf47a 100644 --- a/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx +++ b/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx @@ -30,12 +30,12 @@ export default function LeaderboardItem({ useEffect(() => { const getName = async () => { - const { name, avatar: userAvatar } = await resolveAddressToWalletData( - address - ) + const data = await resolveAddressToWalletData(address) - if (name) setUsername(name) - if (userAvatar) setWalletAvatar(userAvatar) + if (!data) return + + if (data.name) setUsername(data.name) + if (data.avatar) setWalletAvatar(data.avatar) } getName() }, [address]) From e190b1aa968fe57a50172a719791801c62b39266 Mon Sep 17 00:00:00 2001 From: Jagoda Berry Rybacka Date: Fri, 3 Nov 2023 13:14:52 +0100 Subject: [PATCH 08/11] Fix names resolution types --- src/shared/utils/names.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shared/utils/names.ts b/src/shared/utils/names.ts index 5af5a1931..2d4269fc5 100644 --- a/src/shared/utils/names.ts +++ b/src/shared/utils/names.ts @@ -16,7 +16,7 @@ const NAMES_CACHE_STRORAGE_KEY = "taho.cachedNames" const MAX_CACHE_AGE = 1000 * 60 * 60 * 24 * 7 // 1 week const resolveAddressPromiseCache: { - [address: string]: Promise + [address: string]: Promise } = {} const getCachedNames = () => { @@ -72,10 +72,13 @@ const resolveAddressToWalletDataWithoutCache = async (address: string) => { resolveENSPromise(normalizedAddress), resolveUNSPromise(normalizedAddress), resolveUnknownNamePromise(), - ]) as Promise + ]) } - const { name, avatar } = await resolveAddressPromiseCache[normalizedAddress] + const cachedResult = + (await resolveAddressPromiseCache[normalizedAddress]) ?? {} + + const { name, avatar } = cachedResult return name ? { name, avatar } : null } From cfa7a1cfa9946f8b601ca2f603bb74d284f09be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 6 Nov 2023 08:58:47 +0100 Subject: [PATCH 09/11] Split redux selectors --- src/redux-state/selectors/claim.ts | 16 -- src/redux-state/selectors/island.ts | 204 ----------------------- src/redux-state/selectors/leaderboard.ts | 19 +++ src/redux-state/selectors/population.ts | 31 ++++ src/redux-state/selectors/realm.ts | 48 ++++++ src/redux-state/selectors/season.ts | 79 +++++++++ src/redux-state/selectors/staking.ts | 43 +++++ src/redux-state/selectors/token.ts | 39 +++++ src/redux-state/selectors/wallet.ts | 49 +----- src/redux-state/selectors/xp.ts | 16 ++ 10 files changed, 281 insertions(+), 263 deletions(-) create mode 100644 src/redux-state/selectors/leaderboard.ts create mode 100644 src/redux-state/selectors/population.ts create mode 100644 src/redux-state/selectors/realm.ts create mode 100644 src/redux-state/selectors/season.ts create mode 100644 src/redux-state/selectors/staking.ts create mode 100644 src/redux-state/selectors/token.ts create mode 100644 src/redux-state/selectors/xp.ts diff --git a/src/redux-state/selectors/claim.ts b/src/redux-state/selectors/claim.ts index e8bfd2ec4..208267586 100644 --- a/src/redux-state/selectors/claim.ts +++ b/src/redux-state/selectors/claim.ts @@ -1,11 +1,7 @@ -import { createSelector } from "@reduxjs/toolkit" import { RootState } from "redux-state/reducers" import { truncateAddress } from "shared/utils" -import { RealmData } from "shared/types" import { createClaimSelector } from "redux-state/selectors" -import { selectRealmById } from "./island" -/* Base selectors */ export const selectHasClaimed = createClaimSelector("hasClaimed") export const selectEligibility = createClaimSelector("eligibility") export const selectRealmId = createClaimSelector("selectedRealmId") @@ -20,19 +16,7 @@ export const selectRepresentativeAddress = createClaimSelector( export const selectClaimingSelectedRealmId = createClaimSelector("selectedRealmId") -/* User selectors */ export const selectClaimingUser = (state: RootState) => ({ name: selectClaimName(state) || truncateAddress(selectClaimAdress(state)), address: selectClaimAdress(state), }) - -/* Staking selectors */ -export const selectStakingData = createSelector( - (state: RootState) => - selectRealmById(state, selectClaimingSelectedRealmId(state)), - (state: RootState) => selectClaimingStakeAmount(state), - (realmData: RealmData | null, stakeAmount) => ({ - realmContractAddress: realmData ? realmData.realmContractAddress : null, - stakeAmount, - }) -) diff --git a/src/redux-state/selectors/island.ts b/src/redux-state/selectors/island.ts index cda8444fc..3dd348a58 100644 --- a/src/redux-state/selectors/island.ts +++ b/src/redux-state/selectors/island.ts @@ -1,217 +1,13 @@ import { createSelector } from "@reduxjs/toolkit" -import { DAY } from "shared/constants" -import { isSameAddress } from "shared/utils" import { createIslandSelector } from "redux-state/selectors" import { IslandModeType } from "redux-state/slices/island" -import { RealmData, SeasonInfo } from "shared/types" -import { RootState } from "redux-state/reducers" -type SeasonInfoProperty = ( - value: K -) => (state: RootState) => SeasonInfo[K] | undefined - -type DisplayedRealmProperty = ( - value: K -) => (state: RootState) => RealmData[K] | undefined - -/* Base selectors */ export const selectIslandMode = createIslandSelector("mode") export const selectIslandOverlay = createIslandSelector("overlay") export const selectIslandZoomLevel = createIslandSelector("zoomLevel") -export const selectRealms = createIslandSelector("realms") -export const selectSeasonInfo = createIslandSelector("seasonInfo") -export const selectDisplayedRealmId = createIslandSelector("displayedRealmId") -export const selectLeaderboards = createIslandSelector("leaderboards") -export const selectUnclaimedXp = createIslandSelector("unclaimedXp") -export const selectStakeUnlockTime = createIslandSelector("stakeUnlockTime") -export const selectStakingRealmId = createIslandSelector("stakingRealmId") -/* Helpers */ const checkIslandMode = (value: IslandModeType) => createSelector(selectIslandMode, (mode) => mode === value) -const selectSeasonInfoProperty: SeasonInfoProperty = (value) => - createSelector(selectSeasonInfo, (seasonInfo) => - seasonInfo ? seasonInfo[value] : undefined - ) - -const selectDisplayedRealmProperty: DisplayedRealmProperty = (value) => - createSelector(selectRealms, selectDisplayedRealmId, (realms, realmId) => - realmId && realms[realmId] ? realms[realmId][value] : undefined - ) - -const getPopulationOfRealms = (realms: RealmData[]) => - realms.map((realm) => realm.population) - -/* Island info - selectors */ export const selectIsDefaultIslandMode = checkIslandMode("default") export const selectIsJoinRealmIslandMode = checkIslandMode("join-realm") - -/* Realms info - selectors */ -export const selectRealmById = createSelector( - [selectRealms, (_, realmId: string | null) => realmId], - (realms, realmId) => (realmId ? realms[realmId] : null) -) - -export const selectRealmNameById = createSelector( - [selectRealms, (_, realmId: string | null) => realmId], - (realms, realmId) => (realmId ? realms[realmId].name : null) -) - -export const selectRealmWithIdByAddress = createSelector( - [selectRealms, (_, realmAddress: string) => realmAddress], - (realms, realmAddress) => - Object.entries(realms).find(([_, { realmContractAddress }]) => - isSameAddress(realmContractAddress, realmAddress) - ) -) - -export const selectHasLoadedRealmData = createSelector( - selectRealms, - (realms) => Object.keys(realms).length !== 0 -) - -export const selectHasLoadedSeasonInfo = createSelector( - selectSeasonInfo, - (seasonInfo) => seasonInfo !== null -) - -/* Season info - selectors */ -export const selectSeasonStartTimestamp = selectSeasonInfoProperty( - "seasonStartTimestamp" -) - -export const selectSeasonEndTimestamp = - selectSeasonInfoProperty("seasonEndTimestamp") - -export const selectSeasonDurationInWeeks = - selectSeasonInfoProperty("durationInWeeks") - -export const selectIsEndOfSeason = createSelector( - selectSeasonEndTimestamp, - (seasonEndTimestamp) => - seasonEndTimestamp ? Date.now() > seasonEndTimestamp : null -) - -export const selectSeasonWeek = createSelector( - selectSeasonStartTimestamp, - selectIsEndOfSeason, - selectSeasonDurationInWeeks, - (seasonStartTimestamp, isEndOfSeason, durationInWeeks) => { - if (isEndOfSeason) return durationInWeeks - - if (seasonStartTimestamp && durationInWeeks) { - const hasSeasonStarted = seasonStartTimestamp < Date.now() - if (!hasSeasonStarted) return 1 // if the start date is placed in the future, set season week to 1 - - return Math.trunc((Date.now() - seasonStartTimestamp) / (7 * DAY) + 1) - } - - return null - } -) - -export const selectWeekStartDate = createSelector( - selectSeasonStartTimestamp, - selectSeasonWeek, - (seasonStartTimestamp, seasonWeek) => { - if (seasonStartTimestamp && seasonWeek) { - const startDate = new Date(seasonStartTimestamp) - startDate.setDate(startDate.getDate() + (seasonWeek - 1) * 7) - return startDate - } - return null - } -) - -export const selectWeekEndDate = createSelector( - selectWeekStartDate, - (startDate) => { - if (!startDate) return null - - const endDate = new Date(startDate) - endDate.setDate(startDate.getDate() + 6) - return endDate - } -) - -/* Displayed Realm - selectors */ -export const selectDisplayedRealmAddress = selectDisplayedRealmProperty( - "realmContractAddress" -) - -export const selectDisplayedRealmVeTokenAddress = selectDisplayedRealmProperty( - "veTokenContractAddress" -) - -/* Staking Realm - selectors */ -export const selectStakingRealmAddress = createSelector( - selectRealms, - selectStakingRealmId, - (realms, stakingRealmId) => - stakingRealmId && realms[stakingRealmId]?.realmContractAddress -) - -/* Leaderboard selectors */ -const selectLeaderboardDataById = createSelector( - [(_, realmId: string) => realmId, selectLeaderboards], - (realmId, leaderboards) => leaderboards[realmId] -) - -export const selectLeaderboardById = createSelector( - selectLeaderboardDataById, - (leaderboardData) => leaderboardData?.leaderboard ?? [] -) - -export const selectUserLeaderboardRankById = createSelector( - selectLeaderboardDataById, - (leaderboardData) => leaderboardData?.currentUser ?? null -) - -/* Xp selectors */ -export const selectUnclaimedXpById = createSelector( - [(_, realmId: string) => realmId, selectUnclaimedXp], - (realmId, unclaimedXp) => unclaimedXp[realmId] -) - -export const selectUnclaimedXpSumById = createSelector( - [selectUnclaimedXpById], - (unclaimedXp) => - unclaimedXp?.reduce((acc, item) => acc + BigInt(item.claim.amount), 0n) ?? - 0n -) -/* Population selectors */ -export const selectSortedPopulation = createSelector(selectRealms, (realms) => { - const realmsData = Object.entries(realms).map(([id, data]) => ({ - id, - ...data, - })) - - return realmsData.sort((a, b) => a.population - b.population) -}) - -export const selectPopulationById = createSelector( - selectRealmById, - (realm) => realm?.population ?? 0 -) - -export const selectTotalPopulation = createSelector( - selectSortedPopulation, - (realms) => - realms.length ? getPopulationOfRealms(realms).reduce((a, b) => a + b) : 0 -) - -export const selectMaxPopulation = createSelector( - selectSortedPopulation, - (realms) => (realms.length ? Math.max(...getPopulationOfRealms(realms)) : 0) -) - -/* Helpful selectors */ -export const selectIsStakingRealmDisplayed = createSelector( - selectStakingRealmAddress, - selectDisplayedRealmAddress, - (stakingAddress, displayedAddress) => - !!stakingAddress && - !!displayedAddress && - isSameAddress(stakingAddress, displayedAddress) -) diff --git a/src/redux-state/selectors/leaderboard.ts b/src/redux-state/selectors/leaderboard.ts new file mode 100644 index 000000000..0d2995d5d --- /dev/null +++ b/src/redux-state/selectors/leaderboard.ts @@ -0,0 +1,19 @@ +import { createSelector } from "@reduxjs/toolkit" +import { createIslandSelector } from "redux-state/selectors" + +export const selectLeaderboards = createIslandSelector("leaderboards") + +const selectLeaderboardDataById = createSelector( + [(_, realmId: string) => realmId, selectLeaderboards], + (realmId, leaderboards) => leaderboards[realmId] +) + +export const selectLeaderboardById = createSelector( + selectLeaderboardDataById, + (leaderboardData) => leaderboardData?.leaderboard ?? [] +) + +export const selectUserLeaderboardRankById = createSelector( + selectLeaderboardDataById, + (leaderboardData) => leaderboardData?.currentUser ?? null +) diff --git a/src/redux-state/selectors/population.ts b/src/redux-state/selectors/population.ts new file mode 100644 index 000000000..a13a8f625 --- /dev/null +++ b/src/redux-state/selectors/population.ts @@ -0,0 +1,31 @@ +import { createSelector } from "@reduxjs/toolkit" +import { RealmData } from "shared/types" +import { selectRealmById, selectRealms } from "./realm" + +const getPopulationOfRealms = (realms: RealmData[]) => + realms.map((realm) => realm.population) + +export const selectSortedPopulation = createSelector(selectRealms, (realms) => { + const realmsData = Object.entries(realms).map(([id, data]) => ({ + id, + ...data, + })) + + return realmsData.sort((a, b) => a.population - b.population) +}) + +export const selectPopulationById = createSelector( + selectRealmById, + (realm) => realm?.population ?? 0 +) + +export const selectTotalPopulation = createSelector( + selectSortedPopulation, + (realms) => + realms.length ? getPopulationOfRealms(realms).reduce((a, b) => a + b) : 0 +) + +export const selectMaxPopulation = createSelector( + selectSortedPopulation, + (realms) => (realms.length ? Math.max(...getPopulationOfRealms(realms)) : 0) +) diff --git a/src/redux-state/selectors/realm.ts b/src/redux-state/selectors/realm.ts new file mode 100644 index 000000000..1ae0eba20 --- /dev/null +++ b/src/redux-state/selectors/realm.ts @@ -0,0 +1,48 @@ +import { createSelector } from "@reduxjs/toolkit" +import { RootState } from "redux-state/reducers" +import { createIslandSelector } from "redux-state/selectors" +import { RealmData } from "shared/types" +import { isSameAddress } from "shared/utils" + +type DisplayedRealmProperty = ( + value: K +) => (state: RootState) => RealmData[K] | undefined + +export const selectRealms = createIslandSelector("realms") +export const selectDisplayedRealmId = createIslandSelector("displayedRealmId") + +const selectDisplayedRealmProperty: DisplayedRealmProperty = (value) => + createSelector(selectRealms, selectDisplayedRealmId, (realms, realmId) => + realmId && realms[realmId] ? realms[realmId][value] : undefined + ) + +export const selectRealmById = createSelector( + [selectRealms, (_, realmId: string | null) => realmId], + (realms, realmId) => (realmId ? realms[realmId] : null) +) + +export const selectRealmNameById = createSelector( + [selectRealms, (_, realmId: string | null) => realmId], + (realms, realmId) => (realmId ? realms[realmId].name : null) +) + +export const selectRealmWithIdByAddress = createSelector( + [selectRealms, (_, realmAddress: string) => realmAddress], + (realms, realmAddress) => + Object.entries(realms).find(([_, { realmContractAddress }]) => + isSameAddress(realmContractAddress, realmAddress) + ) +) + +export const selectHasLoadedRealmData = createSelector( + selectRealms, + (realms) => Object.keys(realms).length !== 0 +) + +export const selectDisplayedRealmAddress = selectDisplayedRealmProperty( + "realmContractAddress" +) + +export const selectDisplayedRealmVeTokenAddress = selectDisplayedRealmProperty( + "veTokenContractAddress" +) diff --git a/src/redux-state/selectors/season.ts b/src/redux-state/selectors/season.ts new file mode 100644 index 000000000..e7c203771 --- /dev/null +++ b/src/redux-state/selectors/season.ts @@ -0,0 +1,79 @@ +import { createSelector } from "@reduxjs/toolkit" +import { RootState } from "redux-state/reducers" +import { createIslandSelector } from "redux-state/selectors" +import { DAY } from "shared/constants" +import { SeasonInfo } from "shared/types" + +type SeasonInfoProperty = ( + value: K +) => (state: RootState) => SeasonInfo[K] | undefined + +export const selectSeasonInfo = createIslandSelector("seasonInfo") + +const selectSeasonInfoProperty: SeasonInfoProperty = (value) => + createSelector(selectSeasonInfo, (seasonInfo) => + seasonInfo ? seasonInfo[value] : undefined + ) + +export const selectHasLoadedSeasonInfo = createSelector( + selectSeasonInfo, + (seasonInfo) => seasonInfo !== null +) + +export const selectSeasonStartTimestamp = selectSeasonInfoProperty( + "seasonStartTimestamp" +) + +export const selectSeasonEndTimestamp = + selectSeasonInfoProperty("seasonEndTimestamp") + +export const selectSeasonDurationInWeeks = + selectSeasonInfoProperty("durationInWeeks") + +export const selectIsEndOfSeason = createSelector( + selectSeasonEndTimestamp, + (seasonEndTimestamp) => + seasonEndTimestamp ? Date.now() > seasonEndTimestamp : null +) + +export const selectSeasonWeek = createSelector( + selectSeasonStartTimestamp, + selectIsEndOfSeason, + selectSeasonDurationInWeeks, + (seasonStartTimestamp, isEndOfSeason, durationInWeeks) => { + if (isEndOfSeason) return durationInWeeks + + if (seasonStartTimestamp && durationInWeeks) { + const hasSeasonStarted = seasonStartTimestamp < Date.now() + if (!hasSeasonStarted) return 1 // if the start date is placed in the future, set season week to 1 + + return Math.trunc((Date.now() - seasonStartTimestamp) / (7 * DAY) + 1) + } + + return null + } +) + +export const selectWeekStartDate = createSelector( + selectSeasonStartTimestamp, + selectSeasonWeek, + (seasonStartTimestamp, seasonWeek) => { + if (seasonStartTimestamp && seasonWeek) { + const startDate = new Date(seasonStartTimestamp) + startDate.setDate(startDate.getDate() + (seasonWeek - 1) * 7) + return startDate + } + return null + } +) + +export const selectWeekEndDate = createSelector( + selectWeekStartDate, + (startDate) => { + if (!startDate) return null + + const endDate = new Date(startDate) + endDate.setDate(startDate.getDate() + 6) + return endDate + } +) diff --git a/src/redux-state/selectors/staking.ts b/src/redux-state/selectors/staking.ts new file mode 100644 index 000000000..940954719 --- /dev/null +++ b/src/redux-state/selectors/staking.ts @@ -0,0 +1,43 @@ +import { createSelector } from "@reduxjs/toolkit" +import { createIslandSelector } from "redux-state/selectors" +import { isSameAddress } from "shared/utils" +import { RootState } from "redux-state/reducers" +import { RealmData } from "shared/types" +import { + selectDisplayedRealmAddress, + selectRealmById, + selectRealms, +} from "./realm" +import { + selectClaimingSelectedRealmId, + selectClaimingStakeAmount, +} from "./claim" + +export const selectStakingRealmId = createIslandSelector("stakingRealmId") +export const selectStakeUnlockTime = createIslandSelector("stakeUnlockTime") + +export const selectStakingRealmAddress = createSelector( + selectRealms, + selectStakingRealmId, + (realms, stakingRealmId) => + stakingRealmId && realms[stakingRealmId]?.realmContractAddress +) + +export const selectIsStakingRealmDisplayed = createSelector( + selectStakingRealmAddress, + selectDisplayedRealmAddress, + (stakingAddress, displayedAddress) => + !!stakingAddress && + !!displayedAddress && + isSameAddress(stakingAddress, displayedAddress) +) + +export const selectStakingData = createSelector( + (state: RootState) => + selectRealmById(state, selectClaimingSelectedRealmId(state)), + selectClaimingStakeAmount, + (realmData: RealmData | null, stakeAmount) => ({ + realmContractAddress: realmData ? realmData.realmContractAddress : null, + stakeAmount, + }) +) diff --git a/src/redux-state/selectors/token.ts b/src/redux-state/selectors/token.ts new file mode 100644 index 000000000..c818a5dd0 --- /dev/null +++ b/src/redux-state/selectors/token.ts @@ -0,0 +1,39 @@ +import { createSelector } from "@reduxjs/toolkit" +import { createWalletSelector } from "redux-state/selectors" +import { TAHO_SYMBOL } from "shared/constants" + +export const selectTokenBalances = createWalletSelector("balances") + +export const selectTokenBalanceByAddress = createSelector( + [selectTokenBalances, (_, tokenAddress) => tokenAddress], + (balances, tokenAddress) => balances[tokenAddress]?.balance ?? 0n +) + +export const selectTokenSymbolByAddress = createSelector( + [selectTokenBalances, (_, tokenAddress) => tokenAddress], + (balances, tokenAddress) => balances[tokenAddress]?.symbol ?? "" +) + +export const selectTokenBalanceBySymbol = createSelector( + [selectTokenBalances, (_, tokenSymbol) => tokenSymbol], + (balances, tokenSymbol) => { + const tokenBalance = Object.values(balances).find( + (balance) => balance.symbol === tokenSymbol + ) + return tokenBalance?.balance ?? 0n + } +) + +export const selectHasRelevantTokens = createSelector( + selectTokenBalances, + (balances) => + Object.values(balances).some((balanceData) => { + // relevant tokens are any tokens with "TAHO" symbol + // because this group includes both TAHO and veTAHO tokens + if (balanceData.symbol === TAHO_SYMBOL && !!balanceData.balance) { + return true + } + + return false + }) +) diff --git a/src/redux-state/selectors/wallet.ts b/src/redux-state/selectors/wallet.ts index 57ec89995..b73aa21c3 100644 --- a/src/redux-state/selectors/wallet.ts +++ b/src/redux-state/selectors/wallet.ts @@ -1,63 +1,26 @@ import { createSelector } from "@reduxjs/toolkit" -import { RootState } from "redux-state/reducers" -import { TAHO_SYMBOL } from "shared/constants" import { TransactionProgressStatus } from "shared/types" import { truncateAddress } from "shared/utils" import { createWalletSelector } from "redux-state/selectors" -/* Base selectors */ export const selectWalletAddress = createWalletSelector("address") export const selectWalletAvatar = createWalletSelector("avatar") export const selectWalletNameProperty = createWalletSelector("name") export const selectIsWalletConnected = createWalletSelector("isConnected") -export const selectTokenBalances = createWalletSelector("balances") export const selectHasLoadedBalances = createWalletSelector("hasLoadedBalances") export const selectWalletTransactionStatus = createWalletSelector("transactionStatus") -/* Wallet identification selectors */ -export const selectWalletTruncatedAddress = (state: RootState) => - truncateAddress(selectWalletAddress(state)) - -export const selectWalletName = (state: RootState) => - selectWalletNameProperty(state) || selectWalletTruncatedAddress(state) - -/* Token selectors */ -export const selectTokenBalanceByAddress = createSelector( - [selectTokenBalances, (_, tokenAddress) => tokenAddress], - (balances, tokenAddress) => balances[tokenAddress]?.balance ?? 0n -) - -export const selectTokenSymbolByAddress = createSelector( - [selectTokenBalances, (_, tokenAddress) => tokenAddress], - (balances, tokenAddress) => balances[tokenAddress]?.symbol ?? "" +export const selectWalletTruncatedAddress = createSelector( + selectWalletAddress, + (address: string) => truncateAddress(address) ) -export const selectTokenBalanceBySymbol = createSelector( - [selectTokenBalances, (_, tokenSymbol) => tokenSymbol], - (balances, tokenSymbol) => { - const tokenBalance = Object.values(balances).find( - (balance) => balance.symbol === tokenSymbol - ) - return tokenBalance?.balance ?? 0n - } -) - -export const selectHasRelevantTokens = createSelector( - selectTokenBalances, - (balances) => - Object.values(balances).some((balanceData) => { - // relevant tokens are any tokens with "TAHO" symbol - // because this group includes both TAHO and veTAHO tokens - if (balanceData.symbol === TAHO_SYMBOL && !!balanceData.balance) { - return true - } - - return false - }) +export const selectWalletName = createSelector( + [selectWalletNameProperty, selectWalletTruncatedAddress], + (name, address) => name || address ) -/* Transaction selectors */ export const selectTransactionStatusById = createSelector( [(_, id: string) => id, selectWalletTransactionStatus], (id, transactionStatus) => diff --git a/src/redux-state/selectors/xp.ts b/src/redux-state/selectors/xp.ts new file mode 100644 index 000000000..59dfd9ef7 --- /dev/null +++ b/src/redux-state/selectors/xp.ts @@ -0,0 +1,16 @@ +import { createSelector } from "@reduxjs/toolkit" +import { createIslandSelector } from "redux-state/selectors" + +export const selectUnclaimedXp = createIslandSelector("unclaimedXp") + +export const selectUnclaimedXpById = createSelector( + [(_, realmId: string) => realmId, selectUnclaimedXp], + (realmId, unclaimedXp) => unclaimedXp[realmId] +) + +export const selectUnclaimedXpSumById = createSelector( + [selectUnclaimedXpById], + (unclaimedXp) => + unclaimedXp?.reduce((acc, item) => acc + BigInt(item.claim.amount), 0n) ?? + 0n +) From 3dc8fca4034c4c06ce0df13877b1c49d4ee8abfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Mon, 6 Nov 2023 09:02:22 +0100 Subject: [PATCH 10/11] Update redux selectors imports --- src/redux-state/index.ts | 9 ++++++++- src/ui/Island/index.tsx | 6 ++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/redux-state/index.ts b/src/redux-state/index.ts index 41c6941c4..9c6f2344d 100644 --- a/src/redux-state/index.ts +++ b/src/redux-state/index.ts @@ -23,5 +23,12 @@ export * from "./slices/wallet" export * from "./slices/island" export * from "./selectors/claim" -export * from "./selectors/wallet" export * from "./selectors/island" +export * from "./selectors/leaderboard" +export * from "./selectors/population" +export * from "./selectors/realm" +export * from "./selectors/season" +export * from "./selectors/staking" +export * from "./selectors/token" +export * from "./selectors/wallet" +export * from "./selectors/xp" diff --git a/src/ui/Island/index.tsx b/src/ui/Island/index.tsx index d2198726f..0635d8789 100644 --- a/src/ui/Island/index.tsx +++ b/src/ui/Island/index.tsx @@ -1,8 +1,4 @@ import React, { memo, useCallback, useEffect, useState } from "react" -import { - selectIsDefaultIslandMode, - selectRealmNameById, -} from "redux-state/selectors/island" import RealmModal from "shared/components/RealmModal" import backgroundImg from "public/dapp_island_bg.webp" import { @@ -12,6 +8,8 @@ import { useAssets, } from "shared/hooks" import { + selectRealmNameById, + selectIsDefaultIslandMode, setDisplayedRealmId, useDappDispatch, useDappSelector, From 3c128cc9a892e7e27da7389f7882177451a7e88b Mon Sep 17 00:00:00 2001 From: Piotr Kacprzyk Date: Mon, 6 Nov 2023 16:08:28 +0100 Subject: [PATCH 11/11] Change layout of first message from Scout --- src/ui/Assistant/AssistantContent/AssistantWelcome.tsx | 4 ++-- src/ui/Assistant/AssistantContent/index.tsx | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ui/Assistant/AssistantContent/AssistantWelcome.tsx b/src/ui/Assistant/AssistantContent/AssistantWelcome.tsx index 03fdbcd53..a0d63f1af 100644 --- a/src/ui/Assistant/AssistantContent/AssistantWelcome.tsx +++ b/src/ui/Assistant/AssistantContent/AssistantWelcome.tsx @@ -11,6 +11,7 @@ export default function AssistantWelcome() { <> updateAssistant({ visible: false, type: "default" })} >
Welcome to Subscape, Nomad
@@ -23,8 +24,7 @@ export default function AssistantWelcome() {

- Start exploring by hovering -
over our 5 Beta Realms + Start exploring by hovering over our 5 Beta Realms

diff --git a/src/ui/Assistant/AssistantContent/index.tsx b/src/ui/Assistant/AssistantContent/index.tsx index 91090caf4..e749b31fe 100644 --- a/src/ui/Assistant/AssistantContent/index.tsx +++ b/src/ui/Assistant/AssistantContent/index.tsx @@ -7,12 +7,14 @@ import closeIcon from "shared/assets/icons/s/close.svg" export type AssistantContentProps = { isVisible: boolean close: () => void + style?: React.CSSProperties } export default function AssistantContent({ children, isVisible, close, + style, }: AssistantContentProps & { children: ReactNode }) { const transition = useVisibilityTransition(isVisible) @@ -29,6 +31,7 @@ export default function AssistantContent({ padding: "24px 32px 32px", width: 375, pointerEvents: isVisible ? "all" : "none", + ...style, }} >