Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions src/ui/components/CustomInput/CustomInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const CustomInput = ({
className,
labelAction,
endAction,
inputMode,
type = "text",
}: CustomInputProps) => {
const [hidden, setHidden] = useState(hiddenInput);
Expand Down Expand Up @@ -88,6 +89,7 @@ const CustomInput = ({
onIonBlur={() => handleFocus(false)}
onKeyDown={hideKeyboard}
value={value}
inputMode={inputMode}
/>
{hiddenInput && (
<IonButton
Expand Down
12 changes: 12 additions & 0 deletions src/ui/components/CustomInput/CustomInput.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ type TextFieldTypes =
| "month"
| "datetime-local";

type InputMode =
| "none"
| "text"
| "tel"
| "url"
| "email"
| "numeric"
| "decimal"
| "search"
| undefined;

interface CustomInputProps {
dataTestId: string;
title?: string;
Expand All @@ -36,6 +47,7 @@ interface CustomInputProps {
labelAction?: ReactNode;
endAction?: ReactNode;
type?: TextFieldTypes;
inputMode?: InputMode;
}

export type { CustomInputProps };
8 changes: 4 additions & 4 deletions src/ui/pages/SetupGroupProfile/SetupGroupProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const initialState: GroupInfomation = {
stage: Stage.SetupConnection,
displayNameValue: "",
signer: {
requiredSigners: 0,
recoverySigners: 0,
requiredSigners: null,
recoverySigners: null,
},
scannedConections: [],
selectedConnections: [],
Expand Down Expand Up @@ -88,8 +88,8 @@ const SetupGroupProfile = () => {
stage: isPendingState ? Stage.Pending : Stage.SetupConnection,
displayNameValue: currentProfile.identity.displayName,
signer: {
requiredSigners: 0,
recoverySigners: 0,
requiredSigners: null,
recoverySigners: null,
},
scannedConections: currentProfile.multisigConnections,
selectedConnections: currentProfile.multisigConnections,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ describe("Init group", () => {
expect(setStateMock).toBeCalledWith({
...state,
signer: {
recoverySigners: 1,
requiredSigners: 4,
recoverySigners: null,
requiredSigners: null,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ const InitializeGroup = ({ state, setState }: StageProps) => {
ourIdentifier,
state.selectedConnections as MultisigConnectionDetails[],
{
rotationThreshold: state.signer.recoverySigners,
signingThreshold: state.signer.requiredSigners,
rotationThreshold: state.signer.recoverySigners || 0,
signingThreshold: state.signer.requiredSigners || 0,
}
);
dispatch(setToastMsg(ToastMsgType.GROUP_REQUEST_SEND));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,11 @@ describe("Setup signer modal", () => {
</Provider>
);

fireEvent.focus(getByTestId("threshold-recoverySigners"));
fireEvent.change(getByTestId("threshold-recoverySigners"), {
target: { value: "3" },
});
fireEvent.blur(getByTestId("threshold-recoverySigners"));

await waitFor(() => {
expect(
Expand Down Expand Up @@ -167,9 +169,11 @@ describe("Setup signer modal", () => {
).toBeNull();
});

fireEvent.focus(getByTestId("threshold-requiredSigners"));
fireEvent.change(getByTestId("threshold-requiredSigners"), {
target: { value: "3" },
});
fireEvent.blur(getByTestId("threshold-requiredSigners"));

await waitFor(() => {
expect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,28 @@ const SignerInput = ({
onChange,
maxValue,
}: SignerInputProps) => {
const [touched, setTouched] = useState(false);

const errorMessage = (() => {
if (value < 1) {
if (!touched) return;

if (Number(value) < 1) {
return "setupgroupprofile.initgroup.setsigner.error.min";
}

if (value > maxValue) {
if (Number(value) > maxValue) {
return "setupgroupprofile.initgroup.setsigner.error.max";
}

return null;
})();

const decreaseButtonClass = combineClassNames("decrease-threshold-button", {
inactive: value <= 1,
inactive: Number(value) <= 1,
});

const increaseButtonClass = combineClassNames("increase-threshold-button", {
inactive: maxValue <= value,
inactive: maxValue <= Number(value),
});

const handleClickChange = (name: keyof SignerData, value: number) => {
Expand All @@ -50,8 +54,9 @@ const SignerInput = ({
};

const handleChangeValue = (name: keyof SignerData, value: string) => {
const numberValue = value ? Number(value) : 0;
if (isNaN(numberValue)) return;
const numberValue = value !== "" ? Number(value) : null;

if (numberValue !== null && isNaN(numberValue)) return;

onChange(name, numberValue);
};
Expand All @@ -62,17 +67,22 @@ const SignerInput = ({
title={label}
className="signer-threshold"
dataTestId={`threshold-${name}`}
value={`${value}`}
value={`${value === null ? "" : value}`}
onChangeInput={(value) => handleChangeValue(name, value)}
type="number"
inputMode="numeric"
error={!!errorMessage}
onChangeFocus={(focus) => {
if (!focus) {
setTouched(true);
}
}}
endAction={
<div className="signer-threshold-controls">
<IonButton
shape="round"
className={decreaseButtonClass}
data-testid={`${name}-decrease-threshold-button`}
onClick={() => handleClickChange(name, value - 1)}
onClick={() => handleClickChange(name, Number(value) - 1)}
>
<IonIcon
slot="icon-only"
Expand All @@ -84,7 +94,7 @@ const SignerInput = ({
shape="round"
className={increaseButtonClass}
data-testid={`${name}-increase-threshold-button`}
onClick={() => handleClickChange(name, value + 1)}
onClick={() => handleClickChange(name, Number(value) + 1)}
>
<IonIcon
slot="icon-only"
Expand All @@ -108,8 +118,8 @@ export const SetupSignerModal = ({
onSubmit,
}: SetupSignerModalProps) => {
const [data, setData] = useState<SignerData>({
recoverySigners: 1,
requiredSigners: connectionsLength,
recoverySigners: null,
requiredSigners: null,
});

const handleClose = () => {
Expand All @@ -122,27 +132,28 @@ export const SetupSignerModal = ({
};

const isValidData = useCallback(
(signer: number) => {
return signer >= 1 && signer <= connectionsLength;
(signer: number | null) => {
return signer !== null && signer >= 1 && signer <= connectionsLength;
},
[connectionsLength]
);

useEffect(() => {
if (
isOpen &&
isValidData(currentValue.recoverySigners) &&
isValidData(currentValue.requiredSigners)
isValidData(Number(currentValue.recoverySigners)) &&
isValidData(Number(currentValue.requiredSigners))
)
setData({ ...currentValue });
}, [isOpen, currentValue, isValidData]);

const setField = (name: keyof SignerData, value: number) => {
const setField = (name: keyof SignerData, value: number | null) => {
setData((values) => ({
...values,
[name]: value,
}));
};

return (
<IonModal
isOpen={isOpen}
Expand Down Expand Up @@ -170,8 +181,8 @@ export const SetupSignerModal = ({
)}`}
primaryButtonAction={handleSubmit}
primaryButtonDisabled={
!isValidData(data.recoverySigners) ||
!isValidData(data.requiredSigners)
!isValidData(Number(data.recoverySigners)) ||
!isValidData(Number(data.requiredSigners))
}
/>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
interface SignerData {
requiredSigners: number;
recoverySigners: number;
requiredSigners: number | null;
recoverySigners: number | null;
}

interface SignerInputProps {
label: string;
name: keyof SignerData;
value: number;
value: number | null;
maxValue: number;
onChange: (name: keyof SignerData, value: number) => void;
onChange: (name: keyof SignerData, value: number | null) => void;
}

interface SetupSignerModalProps {
Expand Down