Skip to content

Commit

Permalink
feat(APP-3614): Update ProposalActions component to support actionKey…
Browse files Browse the repository at this point in the history
… property and forward index property (#295)
  • Loading branch information
cgero-eth authored Sep 21, 2024
1 parent cc20249 commit 753b784
Show file tree
Hide file tree
Showing 15 changed files with 52 additions and 33 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Add `IconType.BLOCKCHAIN_WALLETCONNECT` and associated asset
- Add `EmptyState` fallback to ProposalActions when no actions provided
- Support `dropdownItems` property on `ProposalActions` module component to display custom actions
- Update `ProposalActions` component to support `actionKey` property and forward `index` property to sub action
components

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('<ProposalActionChangeMembers /> component', () => {
const createTestComponent = (props?: Partial<IProposalActionChangeMembersProps>) => {
const completeProps: IProposalActionChangeMembersProps = {
action: generateProposalActionChangeMembers(),
index: 0,
...props,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DefinitionList, Heading } from '../../../../../../core';
import { MemberDataListItem } from '../../../../member';
import { useOdsModulesContext } from '../../../../odsModulesProvider';
import { ProposalActionType, type IProposalActionChangeMembers } from '../../proposalActionsTypes';
import {
ProposalActionType,
type IProposalActionChangeMembers,
type IProposalActionComponentProps,
} from '../../proposalActionsTypes';

export interface IProposalActionChangeMembersProps {
/**
* The action to render for Member count adjustment
*/
action: IProposalActionChangeMembers;
}
export interface IProposalActionChangeMembersProps
extends IProposalActionComponentProps<IProposalActionChangeMembers> {}

export const ProposalActionChangeMembers: React.FC<IProposalActionChangeMembersProps> = (props) => {
const { action } = props;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('<ProposalActionChangeSettings /> component', () => {
const createTestComponent = (props?: Partial<IProposalActionChangeSettingsProps>) => {
const completeProps: IProposalActionChangeSettingsProps = {
action: generateProposalActionChangeSettings(),
index: 0,
...props,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ export interface IProposalActionChangeSettingsProps

export const ProposalActionChangeSettings: React.FC<IProposalActionChangeSettingsProps> = (props) => {
const { action } = props;

const { copy } = useOdsModulesContext();

const [toggleValue, setToggleValue] = useState<string | undefined>('existingSettings');

const { proposedSettings, existingSettings } = action;
const settingsToDisplay = toggleValue === 'proposedSettings' ? proposedSettings : existingSettings;
const { copy } = useOdsModulesContext();

return (
<div className="flex w-full flex-col gap-2">
<ToggleGroup value={toggleValue} onChange={setToggleValue} isMultiSelect={false}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,14 @@ type Story = StoryObj<typeof ProposalActionTokenMint>;
* Usage example of the ProposalActions module component with mocked TokenMint actions.
*/
export const Default: Story = {
render: () => {
return (
<ProposalActionTokenMint
action={generateProposalActionTokenMint({
receiver: {
currentBalance: '0',
newBalance: '5',
address: '0x32c2FE388ABbB3e678D44DF6a0471086D705316a',
},
})}
/>
);
args: {
action: generateProposalActionTokenMint({
receiver: {
currentBalance: '0',
newBalance: '5',
address: '0x32c2FE388ABbB3e678D44DF6a0471086D705316a',
},
}),
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('<ProposalActionTokenMint /> component', () => {
const createTestComponent = (props?: Partial<IProposalActionTokenMintProps>) => {
const completeProps: IProposalActionTokenMintProps = {
action: generateProposalActionTokenMint(),
index: 0,
...props,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('<ProposalActionUpdateMetadata /> component', () => {
const createTestComponent = (props?: Partial<IProposalActionUpdateMetadataProps>) => {
const defaultProps: IProposalActionUpdateMetadataProps = {
action: generateProposalActionUpdateMetadata(),
index: 0,
...props,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ type Story = StoryObj<typeof ProposalActionWithdrawToken>;
* Usage example of the ProposalActions module component with mocked TokenWithdraw actions.
*/
export const Default: Story = {
render: () => {
return <ProposalActionWithdrawToken action={generateProposalActionWithdrawToken()} />;
args: {
action: generateProposalActionWithdrawToken(),
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('<ProposalActionWithdrawToken /> component', () => {
const createTestComponent = (props?: Partial<IProposalActionWithdrawTokenProps>) => {
const completeProps: IProposalActionWithdrawTokenProps = {
action: generateProposalActionWithdrawToken(),
index: 0,
...props,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@ export interface IProposalActionsDropdownItem<TAction extends IProposalAction =
/**
* Callback called with the current action on item click.
*/
onClick: (action: TAction) => void;
onClick: (action: TAction, index: number) => void;
}

export interface IProposalActionsProps<TAction extends IProposalAction = IProposalAction> extends IWeb3ComponentProps {
/**
* Actions to render.
*/
actions: TAction[];
/**
* Optional action attribute name to be used as a key, useful for using the component within a form library.
* @default action-{index}
*/
actionKey?: keyof TAction;
/**
* Map of action-type <=> action-name displayed on the action header.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const ProposalActions = <TAction extends IProposalAction = IProposalActio
) => {
const {
actions,
actionKey,
actionNames,
customActionComponents,
emptyStateDescription,
Expand Down Expand Up @@ -55,7 +56,7 @@ export const ProposalActions = <TAction extends IProposalAction = IProposalActio
>
{actions.map((action, index) => (
<ProposalActionsAction
key={`action-${index}`}
key={actionKey != null ? (action[actionKey] as string) : `action-${index}`}
action={action}
index={index}
name={actionNames?.[action.type]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,6 @@ describe('<ProposalActionsAction /> component', () => {
expect(screen.getByTestId(dropdownItems[1].icon)).toBeInTheDocument();

await userEvent.click(dropdownItem);
expect(dropdownItems[0].onClick).toHaveBeenCalledWith(action);
expect(dropdownItems[0].onClick).toHaveBeenCalledWith(action, 0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,26 @@ export const ProposalActionsAction = <TAction extends IProposalAction = IProposa
const itemRef = useRef<HTMLDivElement>(null);

const ActionComponent = useMemo(() => {
const commonProps = { index, ...web3Props };

if (CustomComponent) {
return <CustomComponent action={action} {...web3Props} />;
return <CustomComponent action={action} {...commonProps} />;
}

if (proposalActionsUtils.isWithdrawTokenAction(action)) {
return <ProposalActionWithdrawToken action={action} {...web3Props} />;
return <ProposalActionWithdrawToken action={action} {...commonProps} />;
} else if (proposalActionsUtils.isTokenMintAction(action)) {
return <ProposalActionTokenMint action={action} {...web3Props} />;
return <ProposalActionTokenMint action={action} {...commonProps} />;
} else if (proposalActionsUtils.isUpdateMetadataAction(action)) {
return <ProposalActionUpdateMetadata action={action} {...web3Props} />;
return <ProposalActionUpdateMetadata action={action} {...commonProps} />;
} else if (proposalActionsUtils.isChangeMembersAction(action)) {
return <ProposalActionChangeMembers action={action} {...web3Props} />;
return <ProposalActionChangeMembers action={action} {...commonProps} />;
} else if (proposalActionsUtils.isChangeSettingsAction(action)) {
return <ProposalActionChangeSettings action={action} {...web3Props} />;
return <ProposalActionChangeSettings action={action} {...commonProps} />;
}

return null;
}, [action, CustomComponent, web3Props]);
}, [action, CustomComponent, web3Props, index]);

const [viewMode, setViewMode] = useState(
ActionComponent
Expand Down Expand Up @@ -155,7 +157,7 @@ export const ProposalActionsAction = <TAction extends IProposalAction = IProposa
key={item.label}
icon={item.icon}
iconPosition="left"
onClick={() => item.onClick?.(action)}
onClick={() => item.onClick?.(action, index)}
>
{item.label}
</Dropdown.Item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export interface IProposalActionComponentProps<TAction extends IProposalAction =
* Action to be rendered.
*/
action: TAction;
/**
* Index of the action.
*/
index: number;
}

export type ProposalActionComponent<TAction extends IProposalAction = IProposalAction> = ComponentType<
Expand Down

0 comments on commit 753b784

Please sign in to comment.