Skip to content

Commit 9900d57

Browse files
committed
claude:chore: some mobile support, refactor chain/protocol enum mapping
1 parent a516444 commit 9900d57

7 files changed

Lines changed: 93 additions & 109 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
66
"postCreateCommand": "npm install -g @anthropic-ai/claude-code",
77
"mounts": [
8-
"source=/dev/null,target=${containerWorkspaceFolder}/.env,type=bind,readonly",
98
"source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind",
109
"source=${localEnv:HOME}/.claude.json,target=/home/node/.claude.json,type=bind"
1110
],

src/assets/css/custom.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,31 @@
214214
font-size: 12px;
215215
color: rgba(255, 255, 255, 0.35);
216216
}
217+
218+
/* MOBILE OVERRIDES */
219+
220+
@media only screen and (max-width: 767px) {
221+
/* Tighter reward claim cards */
222+
.reward-claim-card {
223+
flex: 0 0 190px;
224+
padding: 14px;
225+
border-radius: 10px;
226+
}
227+
228+
.reward-claim-card-top {
229+
margin-bottom: 8px;
230+
}
231+
232+
.reward-claim-amount {
233+
font-size: 17px;
234+
margin-bottom: 10px;
235+
}
236+
237+
.reward-claim-details {
238+
margin-bottom: 8px;
239+
}
240+
241+
.reward-claims-carousel {
242+
gap: 10px;
243+
}
244+
}

src/components/ui/delegationUpdates.tsx

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,29 @@ import { ApiResponseDto_PageStatsDto, DelegationDto } from "~/backendApi"
44
import { Formatter } from "~/utils/misc/formatter"
55
import { HashLink } from "../utils/links"
66
import { Diff } from "../pages/diff"
7+
import { Chain, Protocol } from "~/enums"
78
import * as C from "~/constants"
89
import avalanche from "../../assets/images/tokens/AVAX.svg"
910
import flare from "../../assets/images/tokens/FLR.svg"
1011
import songbird from "../../assets/images/tokens/SGB.svg"
1112

12-
13-
function chainToLogoUrl(chain: DelegationDto.chain): string {
14-
if (chain == DelegationDto.chain._0) {
15-
return flare
16-
} else if (chain == DelegationDto.chain._1) {
17-
return songbird
18-
} else {
19-
return avalanche
20-
}
13+
const CHAIN_LOGO: Record<number, string> = {
14+
[Chain.FLARE]: flare,
15+
[Chain.SONGBIRD]: songbird,
16+
[Chain.AVALANCHE]: avalanche,
2117
}
2218

23-
function chainToTransactionUrl(
24-
chain: DelegationDto.chain,
25-
protocol: DelegationDto.protocol,
26-
hash: string
27-
): string {
28-
if (chain == DelegationDto.chain._0) {
29-
if (protocol == DelegationDto.protocol._0) {
19+
function chainToTransactionUrl(chain: number, protocol: number, hash: string): string {
20+
if (chain == Chain.FLARE) {
21+
if (protocol == Protocol.FSP) {
3022
return C.flareEvmTransactionUrl(hash)
31-
} else if (protocol == DelegationDto.protocol._1) {
32-
return C.flarePChainTransactionUrl(hash)
3323
} else {
34-
throw Error(`Invalid protocol ${chain}:${protocol}`)
24+
return C.flarePChainTransactionUrl(hash)
3525
}
36-
} else if (chain == DelegationDto.chain._1) {
26+
} else if (chain == Chain.SONGBIRD) {
3727
return C.songbirdEvmTransactionUrl(hash)
38-
} else if (chain == DelegationDto.chain._2) {
28+
} else if (chain == Chain.AVALANCHE) {
3929
return C.avalanchePChainTransactionUrl(hash)
40-
} else {
41-
throw Error(`Invalid protocol ${chain}:${protocol}`)
42-
}
43-
}
44-
45-
function chainToSymbol(chain: DelegationDto.chain): string {
46-
if (chain == DelegationDto.chain._0) {
47-
return 'FLR'
48-
} else if (chain == DelegationDto.chain._1) {
49-
return 'SGB'
50-
} else {
51-
return 'AVAX'
52-
}
53-
}
54-
55-
function resolveProtocolName(protocol: DelegationDto.protocol): string {
56-
if (protocol == DelegationDto.protocol._0) {
57-
return 'FSP'
58-
} else if (protocol == DelegationDto.protocol._1) {
59-
return 'Validator'
6030
}
6131
}
6232

@@ -83,14 +53,14 @@ const DelegationUpdates = ({ data, isLoading, error }: {
8353
<div>Delegated</div>
8454
<div>Timestamp</div>
8555
{delegations.map((delegation, i) => {
86-
const logo = chainToLogoUrl(delegation.chain)
56+
const logo = CHAIN_LOGO[delegation.chain]
8757
const url = chainToTransactionUrl(delegation.chain, delegation.protocol, delegation.transaction)
8858
const diff = Formatter.number(delegation.delegated)
8959
return <React.Fragment key={i}>
9060
<div><img src={logo} width={25} /></div>
91-
<div>{resolveProtocolName(delegation.protocol)}</div>
61+
<div>{C.PROTOCOL_NAME[delegation.protocol]}</div>
9262
<div><HashLink address={delegation.transaction} url={url} length={5} copy={false} /></div>
93-
<div style={{ textAlign: 'center' }}><Diff diff={diff} unit={chainToSymbol(delegation.chain)} /></div>
63+
<div style={{ textAlign: 'center' }}><Diff diff={diff} unit={C.CHAIN_SYMBOL[delegation.chain]} /></div>
9464
<div>{Formatter.relativeDate(delegation.timestamp)}</div>
9565
</React.Fragment>
9666
})}

src/components/ui/rewardClaims.tsx

Lines changed: 22 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,81 +3,43 @@ import { SpinnerCircular } from "spinners-react"
33
import { ApiResponseDto_PageStatsDto, RewardClaimDto } from "~/backendApi"
44
import { Formatter } from "~/utils/misc/formatter"
55
import { HashLink } from "../utils/links"
6+
import { Chain, Protocol } from "~/enums"
67
import * as C from "~/constants"
78
import avalanche from "../../assets/images/tokens/AVAX.svg"
89
import flare from "../../assets/images/tokens/FLR.svg"
910
import songbird from "../../assets/images/tokens/SGB.svg"
1011

11-
12-
function chainToLogoUrl(chain: RewardClaimDto.chain): string {
13-
if (chain == RewardClaimDto.chain._0) {
14-
return flare
15-
} else if (chain == RewardClaimDto.chain._1) {
16-
return songbird
17-
} else {
18-
return avalanche
19-
}
20-
}
21-
22-
function chainToSymbol(chain: RewardClaimDto.chain): string {
23-
if (chain == RewardClaimDto.chain._0) {
24-
return 'FLR'
25-
} else if (chain == RewardClaimDto.chain._1) {
26-
return 'SGB'
27-
} else {
28-
return 'AVAX'
29-
}
12+
const CHAIN_LOGO: Record<number, string> = {
13+
[Chain.FLARE]: flare,
14+
[Chain.SONGBIRD]: songbird,
15+
[Chain.AVALANCHE]: avalanche,
3016
}
3117

32-
function chainToTransactionUrl(
33-
chain: RewardClaimDto.chain,
34-
protocol: RewardClaimDto.protocol,
35-
hash: string
36-
): string {
37-
if (chain == RewardClaimDto.chain._0) {
38-
if (protocol == RewardClaimDto.protocol._0) {
18+
function chainToTransactionUrl(chain: number, protocol: number, hash: string): string {
19+
if (chain == Chain.FLARE) {
20+
if (protocol == Protocol.FSP) {
3921
return C.flareEvmTransactionUrl(hash)
40-
} else if (protocol == RewardClaimDto.protocol._1) {
41-
return C.flarePChainTransactionUrl(hash)
4222
} else {
43-
throw Error(`Invalid protocol ${chain}:${protocol}`)
23+
return C.flarePChainTransactionUrl(hash)
4424
}
45-
} else if (chain == RewardClaimDto.chain._1) {
25+
} else if (chain == Chain.SONGBIRD) {
4626
return C.songbirdEvmTransactionUrl(hash)
47-
} else if (chain == RewardClaimDto.chain._2) {
27+
} else if (chain == Chain.AVALANCHE) {
4828
return C.avalanchePChainTransactionUrl(hash)
49-
} else {
50-
throw Error(`Invalid protocol ${chain}:${protocol}`)
5129
}
5230
}
5331

54-
function chainToAddressUrl(
55-
chain: RewardClaimDto.chain,
56-
protocol: RewardClaimDto.protocol,
57-
address: string
58-
): string {
59-
if (chain == RewardClaimDto.chain._0) {
60-
if (protocol == RewardClaimDto.protocol._0) {
32+
function chainToAddressUrl(chain: number, protocol: number, address: string): string {
33+
if (chain == Chain.FLARE) {
34+
if (protocol == Protocol.FSP) {
6135
return C.flareEvmAddressUrl(address)
62-
} else if (protocol == RewardClaimDto.protocol._1) {
63-
return C.flarePChainAddressUrl(address)
6436
} else {
65-
throw Error(`Invalid protocol ${chain}:${protocol}`)
37+
return C.flarePChainAddressUrl(address)
6638
}
67-
} else if (chain == RewardClaimDto.chain._1) {
39+
} else if (chain == Chain.SONGBIRD) {
6840
return C.songbirdEvmAddressUrl(address)
69-
} else if (chain == RewardClaimDto.chain._2) {
41+
} else if (chain == Chain.AVALANCHE) {
7042
return C.avalanchePChainAddressUrl(address)
71-
} else {
72-
throw Error(`Invalid protocol ${chain}:${protocol}`)
73-
}
74-
}
75-
76-
function resolveProtocolName(protocol: RewardClaimDto.protocol): string {
77-
if (protocol == RewardClaimDto.protocol._0) {
78-
return 'FSP'
79-
} else if (protocol == RewardClaimDto.protocol._1) {
80-
return 'Validator'
8143
}
8244
}
8345

@@ -113,26 +75,26 @@ const RewardClaims = ({ data, isLoading, error }: {
11375
</div>
11476
<div className="reward-claims-carousel" ref={scrollRef}>
11577
{rewards.map((reward, i) => {
116-
const logo = chainToLogoUrl(reward.chain)
117-
const symbol = chainToSymbol(reward.chain)
78+
const logo = CHAIN_LOGO[reward.chain]
79+
const symbol = C.CHAIN_SYMBOL[reward.chain]
11880
const txUrl = chainToTransactionUrl(reward.chain, reward.protocol, reward.transaction)
11981
const addrUrl = chainToAddressUrl(reward.chain, reward.protocol, reward.recipient)
12082
return <div className="reward-claim-card" key={i}>
12183
<div className="reward-claim-card-top">
12284
<img src={logo} width={28} alt={symbol} />
123-
<span className="reward-claim-protocol">{resolveProtocolName(reward.protocol)}</span>
85+
<span className="reward-claim-protocol">{C.PROTOCOL_NAME[reward.protocol]}</span>
12486
</div>
12587
<div className="reward-claim-amount">
12688
+{Formatter.number(reward.reward)} <span className="reward-claim-symbol">{symbol}</span>
12789
</div>
12890
<div className="reward-claim-details">
12991
<div className="reward-claim-row">
13092
<span className="reward-claim-label">Tx</span>
131-
<HashLink address={reward.transaction} url={txUrl} length={6} copy={true} />
93+
<HashLink address={reward.transaction} url={txUrl} length={6} copy={false} />
13294
</div>
13395
<div className="reward-claim-row">
13496
<span className="reward-claim-label">To</span>
135-
<HashLink address={reward.recipient} url={addrUrl} length={6} copy={true} />
97+
<HashLink address={reward.recipient} url={addrUrl} length={6} copy={false} />
13698
</div>
13799
</div>
138100
<div className="reward-claim-time">{Formatter.relativeDate(reward.timestamp)}</div>

src/constants.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1+
import { Chain, Protocol } from './enums'
2+
13
export const MAX_BIPS = 10_000
24
export const NUMBER_DISPLAY_LENGTH = 3
35

6+
// chain & protocol name maps (keyed by API numeric IDs)
7+
8+
export const CHAIN_NAME: Record<number, string> = {
9+
[Chain.FLARE]: 'Flare',
10+
[Chain.SONGBIRD]: 'Songbird',
11+
[Chain.AVALANCHE]: 'Avalanche',
12+
}
13+
14+
export const PROTOCOL_NAME: Record<number, string> = {
15+
[Protocol.FSP]: 'FSP',
16+
[Protocol.VALIDATOR]: 'Validator',
17+
}
18+
419
// server query
520
export const REFRESH_QUERY_FAST_MS = 10_000
621
export const REFRESH_QUERY_SLOW_MS = 30_000
@@ -18,6 +33,12 @@ export const WSGB_SYMBOL = 'WSGB'
1833
export const AVAX_DECIMALS = 18
1934
export const AVAX_SYMBOL = 'AVAX'
2035

36+
export const CHAIN_SYMBOL: Record<number, string> = {
37+
[Chain.FLARE]: FLR_SYMBOL,
38+
[Chain.SONGBIRD]: SGB_SYMBOL,
39+
[Chain.AVALANCHE]: AVAX_SYMBOL,
40+
}
41+
2142
// flare fsp
2243

2344
export const wrappedFlrAdr = '0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d'

src/enums.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ export enum StatusCode {
66

77
export type Status = StatusCode | string
88

9-
export enum Chain { FLARE, SONGBIRD, AVALANCHE }
9+
export enum Chain { FLARE, SONGBIRD, AVALANCHE }
10+
11+
export enum Protocol { FSP, VALIDATOR }

src/utils/data/proposals.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import * as C from "../../constants"
55
function structureApyData(apys: ApyDto[]): Map<string, Map<string, number>> {
66
const mp = new Map()
77
for (const apy of apys) {
8-
if (mp.get(apy.chain) == null) {
9-
mp.set(apy.chain, new Map())
8+
const chain = C.CHAIN_NAME[apy.chain]
9+
if (mp.get(chain) == null) {
10+
mp.set(chain, new Map())
1011
}
11-
mp.get(apy.chain).set(apy.protocol, apy.apy)
12+
const protocol = C.PROTOCOL_NAME[apy.protocol]
13+
mp.get(chain).set(protocol, apy.apy)
1214
}
1315
return mp
1416
}

0 commit comments

Comments
 (0)