Skip to content

Commit e349f12

Browse files
authored
Merge pull request #21 from aragon/f/ui-improvements-4
F/UI improvements 4
2 parents a947305 + 6d0fbc4 commit e349f12

File tree

4 files changed

+75
-38
lines changed

4 files changed

+75
-38
lines changed

components/input/function-abi-select-form.tsx

+26-18
Original file line numberDiff line numberDiff line change
@@ -136,30 +136,38 @@ const FunctionSelect = ({
136136
functionAbiList: AbiFunction[];
137137
onSelect: (f: AbiFunction) => any;
138138
}) => {
139+
const [showReadOnly, setShowReadOnly] = useState(false);
140+
const readonlyCount = functionAbiList.filter((f) => ["pure", "view"].includes(f.stateMutability)).length;
141+
139142
return (
140143
<InputContainer id="func-abi-select" label="Select the function to call" className="my-4">
141144
<dl className="w-full divide-y divide-neutral-100">
142145
{functionAbiList.map((func, idx) => (
143-
<If not={["pure", "view"].includes(func.stateMutability)} key={idx}>
144-
<Then>
145-
<div
146-
onClick={() => onSelect(func)}
147-
className=" flex cursor-pointer flex-col items-baseline gap-y-2 py-3 hover:bg-neutral-50 lg:gap-x-6 lg:py-4"
148-
>
149-
<dd className="size-full px-3 text-base leading-tight text-neutral-500">
150-
{decodeCamelCase(func.name)}
151-
</dd>
152-
</div>
153-
</Then>
154-
<Else>
155-
<div className="flex flex-col items-baseline gap-y-2 py-3 lg:gap-x-6 lg:py-4">
156-
<dd className="size-full px-3 text-base leading-tight text-neutral-500">
157-
{decodeCamelCase(func.name)} <span className="text-xs text-neutral-300">(read only)</span>
158-
</dd>
159-
</div>
160-
</Else>
146+
<If condition={!["pure", "view"].includes(func.stateMutability) || showReadOnly} key={idx}>
147+
<div
148+
onClick={() => onSelect(func)}
149+
className="flex cursor-pointer flex-col items-baseline gap-y-2 py-3 first:rounded-t-xl last:rounded-b-xl hover:bg-neutral-50 lg:gap-x-6 lg:py-4"
150+
>
151+
<dd className="size-full px-3 text-base leading-tight text-neutral-500">
152+
{decodeCamelCase(func.name)}
153+
<If condition={["pure", "view"].includes(func.stateMutability)}>
154+
{" "}
155+
<span className="text-xs text-neutral-300">(read only)</span>
156+
</If>
157+
</dd>
158+
</div>
161159
</If>
162160
))}
161+
<If condition={!showReadOnly && readonlyCount > 0}>
162+
<div
163+
onClick={() => setShowReadOnly(true)}
164+
className="flex cursor-pointer flex-col items-baseline gap-y-2 py-3 first:rounded-t-xl last:rounded-b-xl hover:bg-neutral-50 lg:gap-x-6 lg:py-4"
165+
>
166+
<dd className="size-full px-3 text-base text-sm leading-tight text-neutral-300">
167+
Show read only methods ({readonlyCount})
168+
</dd>
169+
</div>
170+
</If>
163171
</dl>
164172
</InputContainer>
165173
);

components/input/function-params-form.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,6 @@ export const FunctionParamsForm = ({
7777
<p className="text-md font-semibold text-neutral-800">Parameters</p>
7878
</div>
7979
</If>
80-
<If condition={["pure", "view"].includes(functionAbi?.stateMutability ?? "")}>
81-
<div className="">
82-
<AlertInline
83-
message="This function is marked as read only. An action sent to it will have no impact"
84-
variant="warning"
85-
/>
86-
</div>
87-
</If>
8880
{functionAbi?.inputs.map((paramAbi, i) => (
8981
<div key={i} className=" my-3">
9082
<InputParameter abi={paramAbi} idx={i} onChange={onParameterChange} />
@@ -101,6 +93,14 @@ export const FunctionParamsForm = ({
10193
/>
10294
</div>
10395
</If>
96+
<If condition={["pure", "view"].includes(functionAbi?.stateMutability ?? "")}>
97+
<div className="mt-2">
98+
<AlertInline
99+
message="This method is marked as read only. An action calling it should have no impact."
100+
variant="warning"
101+
/>
102+
</div>
103+
</If>
104104
</div>
105105
);
106106
};

hooks/useShuffled.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect, useState } from "react";
2+
3+
export function useShuffled<T>(array?: T[] | readonly T[]) {
4+
const [shuffledArray, setShuffledArray] = useState<T[]>([]);
5+
6+
useEffect(() => {
7+
if (!array) return;
8+
9+
// If the length changes, shuffle and update
10+
const newArray = ([] as T[]).concat(array);
11+
newArray.sort(() => (Math.random() >= 0.5 ? 1 : -1));
12+
13+
setShuffledArray(newArray);
14+
}, [array?.length]);
15+
16+
return shuffledArray;
17+
}
+24-12
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1-
import { useReadContract } from "wagmi";
1+
import { useConfig } from "wagmi";
22
import { DelegateAnnouncerAbi } from "@/plugins/members/artifacts/DelegationWall.sol";
3-
import { PUB_CHAIN, PUB_DELEGATION_WALL_CONTRACT_ADDRESS } from "@/constants";
3+
import { PUB_DELEGATION_WALL_CONTRACT_ADDRESS } from "@/constants";
4+
import { readContract } from "@wagmi/core";
5+
import { useQuery } from "@tanstack/react-query";
6+
import { useShuffled } from "@/hooks/useShuffled";
47

58
/** Returns the list of delegates who posted a candidacy */
69
export function useDelegates() {
7-
const {
8-
data: delegates,
9-
status,
10-
refetch,
11-
} = useReadContract({
12-
chainId: PUB_CHAIN.id,
13-
address: PUB_DELEGATION_WALL_CONTRACT_ADDRESS,
14-
abi: DelegateAnnouncerAbi,
15-
functionName: "getCandidateAddresses",
10+
const config = useConfig();
11+
12+
const { data, status, refetch } = useQuery({
13+
queryKey: ["delegate-addresses-list", PUB_DELEGATION_WALL_CONTRACT_ADDRESS],
14+
queryFn: () => {
15+
return readContract(config, {
16+
abi: DelegateAnnouncerAbi,
17+
address: PUB_DELEGATION_WALL_CONTRACT_ADDRESS,
18+
functionName: "getCandidateAddresses",
19+
args: [],
20+
});
21+
},
22+
retry: true,
23+
refetchOnMount: false,
24+
refetchOnReconnect: false,
25+
retryOnMount: true,
26+
staleTime: 1000 * 60 * 10,
1627
});
28+
const shuffledDelegates = useShuffled(data);
1729

18-
return { delegates, status, refetch };
30+
return { delegates: shuffledDelegates, status, refetch };
1931
}

0 commit comments

Comments
 (0)