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

fix: refacto react-hook-form logic for roles based organizations #1471

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { View } from "react-native";

import { RolesMembersSettingsSection } from "./RolesMembersSettingsSection";
Expand All @@ -25,8 +27,10 @@ import {
CreateDaoFormType,
LAUNCHING_PROCESS_STEPS,
ROLES_BASED_ORGANIZATION_STEPS,
RolesMemberSettingFormType,
RolesSettingFormType,
RolesFormType,
RolesMembersFormType,
zodRolesMembersObject,
zodRolesObject,
} from "@/utils/types/organizations";

export const RolesDeployerSteps: React.FC<{
Expand All @@ -49,33 +53,56 @@ export const RolesDeployerSteps: React.FC<{
const network = getNetwork(selectedWallet?.networkId);
const queryClient = useQueryClient();
const { setToast } = useFeedbacks();
const rolesMembersForm = useForm<RolesMembersFormType>({
resolver: zodResolver(zodRolesMembersObject),
defaultValues: {
members: selectedWallet?.address
? [
{
addr: selectedWallet?.address,
weight: "0",
roles: "",
},
]
: [],
},
});
const rolesForm = useForm<RolesFormType>({
resolver: zodResolver(zodRolesObject),
defaultValues: {
roles: [],
},
});
const membersField = useFieldArray({
control: rolesMembersForm.control,
name: "members",
});
const rolesField = useFieldArray({
control: rolesForm.control,
name: "roles",
});

const [configureVotingFormData, setConfigureVotingFormData] =
useState<ConfigureVotingFormType>();
const [rolesSettingsFormData, setRolesSettingsFormData] =
useState<RolesSettingFormType>();
const [memberSettingsFormData, setMemberSettingsFormData] =
useState<RolesMemberSettingFormType>();

const createDaoContract = async (): Promise<boolean> => {
try {
switch (network?.kind) {
case NetworkKind.Gno: {
const name = organizationData?.associatedHandle!;
const roles =
rolesSettingsFormData?.roles?.map((role) => ({
rolesField?.fields?.map((role) => ({
name: role.name.trim(),
color: role.color,
resources: role.resources,
resources: role.resources || [],
})) || [];
const initialMembers = (memberSettingsFormData?.members || []).map(
(member) => ({
address: member.addr,
weight: parseInt(member.weight, 10),
roles: member.roles
? member.roles.split(",").map((role) => role.trim())
: [],
}),
);
const initialMembers = (membersField?.fields || []).map((member) => ({
address: member.addr,
weight: parseInt(member.weight, 10),
roles: member.roles
? member.roles.split(",").map((role) => role.trim())
: [],
}));
const pkgPath = await adenaDeployGnoDAO(
network.id,
selectedWallet?.address!,
Expand Down Expand Up @@ -113,7 +140,7 @@ export const RolesDeployerSteps: React.FC<{
network.cwAdminFactoryContractAddress!;
const walletAddress = selectedWallet.address;

if (!memberSettingsFormData) return false;
if (!membersField.fields) return false;
const params: CreateDaoMemberBasedParams = {
networkId,
sender: walletAddress,
Expand All @@ -127,7 +154,7 @@ export const RolesDeployerSteps: React.FC<{
description: organizationData.organizationDescription,
tns: organizationData.associatedHandle,
imageUrl: organizationData.imageUrl,
members: memberSettingsFormData.members.map((value) => ({
members: membersField.fields.map((value) => ({
addr: value.addr,
weight: parseInt(value.weight, 10),
})),
Expand Down Expand Up @@ -184,13 +211,11 @@ export const RolesDeployerSteps: React.FC<{
setCurrentStep(2);
};

const onSubmitRolesSettings = (data: RolesSettingFormType) => {
setRolesSettingsFormData(data);
const onSubmitRolesSettings = () => {
setCurrentStep(3);
};

const onSubmitMemberSettings = (data: RolesMemberSettingFormType) => {
setMemberSettingsFormData(data);
const onSubmitMemberSettings = () => {
setCurrentStep(4);
};

Expand All @@ -215,8 +240,8 @@ export const RolesDeployerSteps: React.FC<{
);
setOrganizationData(undefined);
setConfigureVotingFormData(undefined);
setRolesSettingsFormData(undefined);
setMemberSettingsFormData(undefined);
rolesMembersForm.reset();
rolesForm.reset();
setCurrentStep(0);
setDAOAddress("");
setLaunchingStep(0);
Expand All @@ -239,14 +264,25 @@ export const RolesDeployerSteps: React.FC<{
currentStep === 2 ? { display: "flex", flex: 1 } : { display: "none" }
}
>
<RolesSettingsSection onSubmit={onSubmitRolesSettings} />
<RolesSettingsSection
remove={rolesField.remove}
append={rolesField.append}
roles={rolesField.fields}
handleSubmit={rolesForm.handleSubmit(onSubmitRolesSettings)}
/>
</View>
<View
style={
currentStep === 3 ? { display: "flex", flex: 1 } : { display: "none" }
}
>
<RolesMembersSettingsSection onSubmit={onSubmitMemberSettings} />
<RolesMembersSettingsSection
members={membersField.fields}
append={membersField.append}
control={rolesMembersForm.control}
remove={membersField.remove}
handleSubmit={rolesMembersForm.handleSubmit(onSubmitMemberSettings)}
/>
</View>
<View
style={
Expand All @@ -256,8 +292,8 @@ export const RolesDeployerSteps: React.FC<{
<RolesReviewInformationSection
organizationData={organizationData}
votingSettingData={configureVotingFormData}
rolesSettingData={rolesSettingsFormData}
memberSettingData={memberSettingsFormData}
rolesSettingData={rolesField.fields}
memberSettingData={membersField.fields}
onSubmit={onStartLaunchingProcess}
/>
</View>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import React from "react";
import { Control, UseFieldArrayAppend } from "react-hook-form";
import { Pressable, ScrollView, View, ViewStyle } from "react-native";
import { z } from "zod";

import trashSVG from "../../../../../assets/icons/trash.svg";
import walletInputSVG from "../../../../../assets/icons/wallet-input.svg";
import useSelectedWallet from "../../../../hooks/useSelectedWallet";

import { BrandText } from "@/components/BrandText";
import { SVG } from "@/components/SVG";
Expand All @@ -18,50 +18,31 @@ import { fontSemibold28 } from "@/utils/style/fonts";
import { layout } from "@/utils/style/layout";
import {
ROLES_BASED_ORGANIZATION_STEPS,
RolesMemberSettingFormType,
RolesMembersFormType,
zodRolesMemberObject,
} from "@/utils/types/organizations";

interface RolesMembersSettingsSectionProps {
onSubmit: (form: RolesMemberSettingFormType) => void;
members: z.infer<typeof zodRolesMemberObject>[];
append: UseFieldArrayAppend<RolesMembersFormType>;
control: Control<RolesMembersFormType>;
remove: (index?: number | number[] | undefined) => void;
handleSubmit: () => void;
}

export const RolesMembersSettingsSection: React.FC<
RolesMembersSettingsSectionProps
> = ({ onSubmit }) => {
const { handleSubmit, control, resetField, unregister } =
useForm<RolesMemberSettingFormType>();

// this effect put the selected wallet address in the first field only on initial load
const selectedWallet = useSelectedWallet();
const [initialReset, setInitialReset] = useState(false);
useEffect(() => {
if (initialReset) {
return;
}
if (!selectedWallet?.address) {
return;
}
resetField("members.0.addr", {
defaultValue: selectedWallet?.address,
});
setInitialReset(true);
}, [selectedWallet?.address, resetField, initialReset]);

const [addressIndexes, setAddressIndexes] = useState<number[]>([0]);

// functions
const removeAddressField = (id: number, index: number) => {
unregister(`members.${index}.addr`);
unregister(`members.${index}.weight`);
unregister(`members.${index}.roles`);
if (addressIndexes.length > 1) {
const copyIndex = [...addressIndexes].filter((i) => i !== id);
setAddressIndexes(copyIndex);
}
> = ({ handleSubmit, append, remove, members, control }) => {
const removeAddressField = (index: number) => {
remove(index);
};

const addAddressField = () => {
setAddressIndexes([...addressIndexes, Math.floor(Math.random() * 200000)]);
append({
addr: "",
weight: "",
roles: "",
});
};

return (
Expand All @@ -70,10 +51,10 @@ export const RolesMembersSettingsSection: React.FC<
<BrandText style={fontSemibold28}>Members</BrandText>
<SpacerColumn size={2.5} />

{addressIndexes.map((id, index) => (
<View style={inputContainerCStyle} key={id.toString()}>
{members.map((member, index) => (
<View style={inputContainerCStyle} key={member.addr}>
<View style={leftInputCStyle}>
<TextInputCustom<RolesMemberSettingFormType>
<TextInputCustom<RolesMembersFormType>
name={`members.${index}.addr`}
noBrokenCorners
label="Member Address"
Expand All @@ -85,15 +66,15 @@ export const RolesMembersSettingsSection: React.FC<
>
<Pressable
style={trashContainerCStyle}
onPress={() => removeAddressField(id, index)}
onPress={() => removeAddressField(index)}
>
<SVG source={trashSVG} width={12} height={12} />
</Pressable>
</TextInputCustom>
</View>
<SpacerRow size={2.5} />
<View style={rightInputCStyle}>
<TextInputCustom<RolesMemberSettingFormType>
<TextInputCustom<RolesMembersFormType>
name={`members.${index}.weight`}
noBrokenCorners
label="Weight"
Expand All @@ -106,7 +87,7 @@ export const RolesMembersSettingsSection: React.FC<
</View>
<SpacerRow size={2.5} />
<View style={rightInputCStyle}>
<TextInputCustom<RolesMemberSettingFormType>
<TextInputCustom<RolesMembersFormType>
name={`members.${index}.roles`}
noBrokenCorners
label="Roles - separate with a comma"
Expand All @@ -125,7 +106,7 @@ export const RolesMembersSettingsSection: React.FC<
<PrimaryButton
size="M"
text={`Next: ${ROLES_BASED_ORGANIZATION_STEPS[4]}`}
onPress={handleSubmit(onSubmit)}
onPress={handleSubmit}
testID="member-settings-next"
/>
</View>
Expand Down
Loading
Loading