Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F/UI improvements 3 #20

Merged
merged 6 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
22 changes: 19 additions & 3 deletions components/proposalActions/proposalActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AccordionItemContent,
AccordionItemHeader,
AvatarIcon,
Button,
IconType,
InputText,
} from "@aragon/ods";
Expand All @@ -26,10 +27,11 @@ interface IProposalActionsProps {
description?: string;
emptyListDescription?: string;
actions?: RawAction[];
onRemove?: (index: number) => any;
}

export const ProposalActions: React.FC<IProposalActionsProps> = (props) => {
const { actions, description, emptyListDescription } = props;
const { actions, description, emptyListDescription, onRemove } = props;

let message: string;
if (actions?.length) {
Expand All @@ -51,14 +53,21 @@ export const ProposalActions: React.FC<IProposalActionsProps> = (props) => {
{/* Content */}
<If condition={actions?.length}>
<AccordionContainer isMulti={true} className="border-t border-t-neutral-100">
{actions?.map((action, index) => <ActionItem key={index} index={index} rawAction={action} />)}
{actions?.map((action, index) => (
<ActionItem
key={index}
index={index}
rawAction={action}
onRemove={onRemove ? () => onRemove?.(index) : undefined}
/>
))}
</AccordionContainer>
</If>
</div>
);
};

const ActionItem = ({ index, rawAction }: { index: number; rawAction: RawAction }) => {
const ActionItem = ({ index, rawAction, onRemove }: { index: number; rawAction: RawAction; onRemove?: () => any }) => {
const action = useAction(rawAction);
const title = `Action ${index + 1}`;
const coinName = PUB_CHAIN.nativeCurrency.symbol;
Expand Down Expand Up @@ -129,6 +138,13 @@ const ActionItem = ({ index, rawAction }: { index: number; rawAction: RawAction
</If>
</Else>
</If>
<If condition={!!onRemove}>
<div className="mt-2">
<Button variant="tertiary" size="sm" iconLeft={IconType.CLOSE} onClick={onRemove}>
Remove action
</Button>
</div>
</If>
</div>
</AccordionItemContent>
</AccordionItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const VotingStageStatus: React.FC<IVotingStageStatus> = (props) => {
<AvatarIcon size="sm" variant="success" icon={IconType.CHECKMARK} className="shrink-0" />
</>
)}
{status === "rejected" && (
{["rejected", "vetoed"].includes(status) && (
<>
<div className="flex flex-grow items-center gap-x-0.5">
<span className="shrink-0 text-neutral-500">The proposal has been</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { iVotesAbi } from "../artifacts/iVotes.sol";
import { iVotesAbi } from "../plugins/members/artifacts/iVotes.sol";
import { PUB_CHAIN, PUB_TOKEN_ADDRESS } from "@/constants";
import { type Address } from "viem";
import { useReadContracts } from "wagmi";

/** Returns the delegate (if any) for the given address */
export const useGovernanceToken = (address?: Address) => {
export const useTokenVotes = (address?: Address) => {
const { data, isLoading, isError, refetch } = useReadContracts({
contracts: [
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
]
},
"dependencies": {
"@aragon/ods": "1.0.39",
"@aragon/ods": "1.0.40",
"@hookform/resolvers": "^3.9.0",
"@react-native-async-storage/async-storage": "^1.23.1",
"@shazow/whatsabi": "^0.13.2",
Expand Down
4 changes: 4 additions & 0 deletions plugins/emergency-multisig/hooks/usePublicKeyRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useQuery } from "@tanstack/react-query";
import { uint8ArrayToHex } from "@/utils/hex";
import { useDerivedWallet } from "../../../hooks/useDerivedWallet";
import { useAlerts } from "@/context/Alerts";
import { debounce } from "@/utils/debounce";

export function usePublicKeyRegistry() {
const config = useConfig();
Expand Down Expand Up @@ -71,6 +72,9 @@ export function usePublicKeyRegistry() {
useEffect(() => {
if (registrationStatus === "idle" || registrationStatus === "pending") return;
else if (registrationStatus === "error") {
// Refetch the status, just in case
debounce(() => refetch(), 800);

if (error?.message?.startsWith("User rejected the request")) {
addAlert("Transaction rejected by the user", {
timeout: 4 * 1000,
Expand Down
15 changes: 12 additions & 3 deletions plugins/emergency-multisig/pages/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export default function Create() {
setActions(actions.concat(newAction));
setAddActionType("");
};
const onRemoveAction = (idx: number) => {
actions.splice(idx, 1);
setActions([].concat(actions as any));
};
const removeResource = (idx: number) => {
resources.splice(idx, 1);
setResources([].concat(resources as any));
Expand All @@ -74,8 +78,9 @@ export default function Create() {
return (
<MainSection narrow>
<div className="w-full justify-between">
<h1 className="mb-10 text-3xl font-semibold text-neutral-900">Create Proposal</h1>

<h1 className="mb-8 line-clamp-1 flex flex-1 shrink-0 text-2xl font-normal leading-tight text-neutral-800 md:text-3xl">
Create Proposal
</h1>
<PlaceHolderOr selfAddress={selfAddress} canCreate={canCreate} isConnected={isConnected}>
<div className="mb-6">
<InputText
Expand Down Expand Up @@ -161,6 +166,7 @@ export default function Create() {
variant="tertiary"
size="lg"
iconLeft={IconType.PLUS}
disabled={isCreating}
onClick={() => {
setResources(resources.concat({ url: "", name: "" }));
}}
Expand All @@ -175,17 +181,20 @@ export default function Create() {
<ProposalActions
actions={actions}
emptyListDescription="The proposal has no actions defined yet. Select a type of action to add to the proposal."
onRemove={(idx) => onRemoveAction(idx)}
/>

<div className="mt-8 grid w-full grid-cols-2 gap-4 md:grid-cols-4">
<AddActionCard
title="Add a payment"
icon={IconType.WITHDRAW}
disabled={isCreating}
onClick={() => setAddActionType("withdrawal")}
/>
<AddActionCard
title="Select a function"
icon={IconType.BLOCKCHAIN_BLOCKCHAIN}
disabled={isCreating}
onClick={() => setAddActionType("select-abi-function")}
/>
<AddActionCard
Expand All @@ -196,8 +205,8 @@ export default function Create() {
/>
<AddActionCard
title="Copy the calldata"
disabled
icon={IconType.COPY}
disabled={isCreating}
onClick={() => setAddActionType("calldata")}
/>
</div>
Expand Down
10 changes: 4 additions & 6 deletions plugins/members/components/DelegateAnnouncementDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ export const DelegateAnnouncementDialog: React.FC<IDelegateAnnouncementDialogPro
const { fields, append, remove } = useFieldArray({ name: DELEGATE_RESOURCES, control });

const onSuccessfulAnnouncement = () => {
setTimeout(() => {
router.push("#/delegates/" + address!);
}, 2000);
router.push("#/delegates/" + address!);
};
const { isConfirming, status, announceDelegation } = useAnnounceDelegation(onSuccessfulAnnouncement);

Expand Down Expand Up @@ -212,6 +210,9 @@ export const DelegateAnnouncementDialog: React.FC<IDelegateAnnouncementDialogPro
</span>
</div>
<div className="mt-4 flex justify-between">
<Button variant="secondary" size="lg" onClick={onClose} disabled={isConfirming || status === "pending"}>
Cancel
</Button>
<Button
variant="primary"
size="lg"
Expand All @@ -220,9 +221,6 @@ export const DelegateAnnouncementDialog: React.FC<IDelegateAnnouncementDialogPro
>
{ctaLabel}
</Button>
<Button variant="secondary" size="lg" onClick={onClose} disabled={isConfirming || status === "pending"}>
Cancel
</Button>
</div>
</DialogContent>
<DialogFooter />
Expand Down
4 changes: 2 additions & 2 deletions plugins/members/components/DelegateListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { formatHexString, equalAddresses } from "@/utils/evm";
import { type IDataListItemProps, DataList, MemberAvatar, Tag } from "@aragon/ods";
import { useAccount } from "wagmi";
import { Address, formatEther } from "viem";
import { useGovernanceToken } from "../hooks/useGovernanceToken";
import { useTokenVotes } from "../../../hooks/useTokenVotes";
import VerifiedDelegates from "../../../verified-delegates.json";
import { useDelegateAnnounce } from "../hooks/useDelegateAnnounce";

Expand All @@ -20,7 +20,7 @@ export const DelegateListItem: React.FC<IDelegateListItemProps> = (props) => {
const { isMyDelegate, avatarSrc, address, ...otherProps } = props;
const { address: currentUserAddress, isConnected } = useAccount();
const isCurrentUser = isConnected && address && equalAddresses(currentUserAddress, address);
const { votingPower } = useGovernanceToken(address);
const { votingPower } = useTokenVotes(address);
const isVerified = VerifiedDelegates.findIndex((d) => equalAddresses(d.address, address)) >= 0;
const { announce } = useDelegateAnnounce(address);

Expand Down
4 changes: 2 additions & 2 deletions plugins/members/components/DelegateMemberList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataList, IllustrationHuman } from "@aragon/ods";
import { DelegateListItem } from "./DelegateListItem";
import { equalAddresses } from "@/utils/evm";
import { useDelegates } from "../hooks/useDelegates";
import { useGovernanceToken } from "../hooks/useGovernanceToken";
import { useTokenVotes } from "../../../hooks/useTokenVotes";
import { useAccount } from "wagmi";
import VerifiedDelegates from "../../../verified-delegates.json";
import { PleaseWaitSpinner } from "@/components/please-wait";
Expand All @@ -20,7 +20,7 @@ export const DelegateMemberList: React.FC<IDelegateMemberListProps> = ({ verifie
const [searchValue, setSearchValue] = useState<string>();
// const [activeSort, setActiveSort] = useState<string>();
const { delegates: fetchedDelegates, status: loadingStatus } = useDelegates();
const { delegatesTo } = useGovernanceToken(address);
const { delegatesTo } = useTokenVotes(address);
const delegates = (fetchedDelegates || []).filter((item) => {
if (!verifiedOnly) return true;
return VerifiedDelegates.findIndex((d) => equalAddresses(d.address, item)) >= 0;
Expand Down
6 changes: 3 additions & 3 deletions plugins/members/components/HeaderMember.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { formatEther, type Address } from "viem";
import { mainnet } from "viem/chains";
import { useAccount, useEnsName } from "wagmi";
import { useGovernanceToken } from "../hooks/useGovernanceToken";
import { useTokenVotes } from "../../../hooks/useTokenVotes";
import { Else, ElseIf, If, Then } from "@/components/if";
import { useWeb3Modal } from "@web3modal/wagmi/react";
import { useDelegateVotingPower } from "../hooks/useDelegateVotingPower";
Expand All @@ -31,8 +31,8 @@ export const HeaderMember: React.FC<IHeaderMemberProps> = (props) => {
const { open } = useWeb3Modal();
const { address: myAddress, isConnected } = useAccount();
const { data: ensName } = useEnsName({ chainId: mainnet.id, address: delegateAddress });
const { votingPower, balance: delegateTokenBalance, refetch } = useGovernanceToken(delegateAddress);
const { delegatesTo } = useGovernanceToken(myAddress);
const { votingPower, balance: delegateTokenBalance, refetch } = useTokenVotes(delegateAddress);
const { delegatesTo } = useTokenVotes(myAddress);
const { delegateVotingPower, isLoading: isConfirming } = useDelegateVotingPower(delegateAddress, refetch);
const formattedAddress = formatHexString(delegateAddress);
const isVerified = VerifiedDelegates.findIndex((d) => equalAddresses(d.address, delegateAddress)) >= 0;
Expand Down
31 changes: 21 additions & 10 deletions plugins/members/hooks/useAnnounceDelegation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { PUB_DELEGATION_WALL_CONTRACT_ADDRESS } from "@/constants";
import { useAlerts } from "@/context/Alerts";
import { logger } from "@/services/logger";
import { uploadToPinata } from "@/utils/ipfs";
import { useCallback, useEffect } from "react";
import { useCallback, useEffect, useState } from "react";
import { toHex } from "viem";
import { useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { type IAnnouncementMetadata } from "../utils/types";

export function useAnnounceDelegation(onSuccess?: () => void) {
const { addAlert } = useAlerts();
const { writeContract, data: hash, error, status } = useWriteContract();
const [uploading, setUploading] = useState(false);
const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ hash });

useEffect(() => {
Expand Down Expand Up @@ -50,18 +51,28 @@ export function useAnnounceDelegation(onSuccess?: () => void) {
async (metadata: IAnnouncementMetadata) => {
if (!metadata) return;

setUploading(true);

try {
const ipfsUrl = await uploadToPinata(JSON.stringify(metadata));

if (ipfsUrl) {
writeContract({
abi: DelegateAnnouncerAbi,
address: PUB_DELEGATION_WALL_CONTRACT_ADDRESS,
functionName: "register",
args: [toHex(ipfsUrl)],
});
}
if (!ipfsUrl) throw new Error("Empty IPFS URL");
setTimeout(() => setUploading(false), 1000);

writeContract({
abi: DelegateAnnouncerAbi,
address: PUB_DELEGATION_WALL_CONTRACT_ADDRESS,
functionName: "register",
args: [toHex(ipfsUrl)],
});
} catch (error) {
setUploading(false);

addAlert("Could not upload the details", {
description: "The profile details could not be pinned on IPFS",
type: "error",
});

logger.error("Could not upload delegate profile metadata to IPFS", error);
}
},
Expand All @@ -71,7 +82,7 @@ export function useAnnounceDelegation(onSuccess?: () => void) {
return {
announceDelegation,
isConfirmed,
isConfirming,
isConfirming: uploading || isConfirming,
status,
};
}
13 changes: 12 additions & 1 deletion plugins/multisig/pages/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export default function Create() {
setActions(actions.concat(newAction));
setAddActionType("");
};
const onRemoveAction = (idx: number) => {
actions.splice(idx, 1);
setActions([].concat(actions as any));
};
const removeResource = (idx: number) => {
resources.splice(idx, 1);
setResources([].concat(resources as any));
Expand All @@ -63,7 +67,9 @@ export default function Create() {
return (
<MainSection narrow>
<div className="w-full justify-between">
<h1 className="mb-10 text-3xl font-semibold text-neutral-900">Create Proposal</h1>
<h1 className="mb-8 line-clamp-1 flex flex-1 shrink-0 text-2xl font-normal leading-tight text-neutral-800 md:text-3xl">
Create Proposal
</h1>

<PlaceHolderOr selfAddress={selfAddress} canCreate={canCreate} isConnected={isConnected}>
<div className="mb-6">
Expand Down Expand Up @@ -150,6 +156,7 @@ export default function Create() {
variant="tertiary"
size="lg"
iconLeft={IconType.PLUS}
disabled={isCreating}
onClick={() => {
setResources(resources.concat({ url: "", name: "" }));
}}
Expand All @@ -164,17 +171,20 @@ export default function Create() {
<ProposalActions
actions={actions}
emptyListDescription="The proposal has no actions defined yet. Select a type of action to add to the proposal."
onRemove={(idx) => onRemoveAction(idx)}
/>

<div className="mt-8 grid w-full grid-cols-2 gap-4 md:grid-cols-4">
<AddActionCard
title="Add a payment"
icon={IconType.WITHDRAW}
disabled={isCreating}
onClick={() => setAddActionType("withdrawal")}
/>
<AddActionCard
title="Select a function"
icon={IconType.BLOCKCHAIN_BLOCKCHAIN}
disabled={isCreating}
onClick={() => setAddActionType("select-abi-function")}
/>
<AddActionCard
Expand All @@ -186,6 +196,7 @@ export default function Create() {
<AddActionCard
title="Copy the calldata"
icon={IconType.COPY}
disabled={isCreating}
onClick={() => setAddActionType("calldata")}
/>
</div>
Expand Down
Loading
Loading