Skip to content

Commit

Permalink
factory tx form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
chalabi2 committed Sep 4, 2024
1 parent e69395d commit 15eb0c2
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 492 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.validate": ["typescript", "typescriptreact"]
"eslint.validate": ["typescript", "typescriptreact"],
"typescript.tsdk": "node_modules/typescript/lib"
}
128 changes: 53 additions & 75 deletions components/factory/forms/CreateDenom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,21 @@ import { TokenAction, TokenFormData } from '@/helpers/formReducer';
import { useTx, useFeeEstimation } from '@/hooks';
import { osmosis } from '@chalabi/manifestjs';
import Link from 'next/link';
import { useState, useEffect } from 'react';
import { useState } from 'react';
import { Formik, Form } from 'formik';
import Yup from '@/utils/yupExtensions';
import { TextInput } from '@/components/react/inputs';

const DenomSchema = Yup.object().shape({
subdenom: Yup.string()
.required('Subdenom is required')
.matches(
/^[uaqg][a-zA-Z0-9]+$/,
'Subdenom must start with u, a, q, or g, followed by letters and numbers'
)
.min(4, 'Subdenom must be at least 4 characters')
.max(44, 'Subdenom must not exceed 44 characters'),
});

export default function CreateDenom({
nextStep,
Expand All @@ -15,53 +29,17 @@ export default function CreateDenom({
dispatch: React.Dispatch<TokenAction>;
address: string;
}>) {
const [error, setError] = useState<string | null>(null);
const [touched, setTouched] = useState(false);

const updateField = (field: keyof TokenFormData, value: any) => {
dispatch({ type: 'UPDATE_FIELD', field, value });
setTouched(true);
};

const { createDenom } = osmosis.tokenfactory.v1beta1.MessageComposer.withTypeUrl;
const [isSigning, setIsSigning] = useState(false);
const { tx } = useTx('manifest');
const { estimateFee } = useFeeEstimation('manifest');

const validateSubdenom = (value: string) => {
console.log('Validating subdenom', value);
if (value.length === 0) {
return 'Subdenom is required';
}
if (!/^[a-zA-Z]/.test(value)) {
return 'Subdenom must start with a letter';
}
if (!/^[a-zA-Z0-9]+$/.test(value)) {
return 'Subdenom can only contain letters and numbers';
}
return null;
};

useEffect(() => {
if (touched) {
const validationError = validateSubdenom(formData.subdenom);
setError(validationError);
}
}, [formData.subdenom, touched]);

const handleConfirm = async () => {
setTouched(true);
const validationError = validateSubdenom(formData.subdenom);
if (validationError) {
setError(validationError);
return;
}

const handleConfirm = async (values: TokenFormData) => {
setIsSigning(true);
try {
const msg = createDenom({
sender: address ?? '',
subdenom: formData.subdenom,
subdenom: values.subdenom,
});

const fee = await estimateFee(address ?? '', [msg]);
Expand All @@ -72,7 +50,6 @@ export default function CreateDenom({
},
});
} catch (error) {
setIsSigning(false);
console.error('Error during transaction setup:', error);
} finally {
setIsSigning(false);
Expand All @@ -87,45 +64,46 @@ export default function CreateDenom({
<h1 className="mb-4 text-2xl font-extrabold tracking-tight sm:mb-6 leding-tight ">
Create Denom
</h1>
<form className=" min-h-[330px]">
<div className="grid gap-5 my-6 sm:grid-cols-2">
<div>
<label htmlFor="denom" className="block mb-2 text-sm font-medium">
Token Sub Denom
</label>
<input
type="text"
aria-label={'denom-input'}
placeholder="udenom"
className={`input input-bordered w-full max-w-xs ${
touched && error ? 'input-error' : ''
}`}
value={formData.subdenom}
onChange={e => updateField('subdenom', e.target.value)}
onBlur={() => setTouched(true)}
/>
{touched && error && (
<p className="mt-2 text-sm text-error" aria-label={'error'}>
{error}
</p>
)}
<Formik
initialValues={formData}
validationSchema={DenomSchema}
onSubmit={handleConfirm}
>
{({ isValid, dirty, setFieldValue }) => (
<Form className="min-h-[330px]">
<div className="grid gap-5 my-6 sm:grid-cols-2">
<TextInput
label="Token Sub Denom"
name="subdenom"
placeholder="udenom"
value={formData.subdenom}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
dispatch({
type: 'UPDATE_FIELD',
field: 'subdenom',
value: e.target.value,
});
setFieldValue('subdenom', e.target.value);
}}
/>
</div>
<p className="mt-2 text-sm text-gray-500">
We recommend starting with &apos;u&apos; (e.g., &apos;utoken&apos;)
</p>
</div>
</div>
</form>
<button
onClick={handleConfirm}
className="w-full btn px-5 py-2.5 sm:py-3.5 btn-primary"
disabled={!formData.subdenom || (touched && !!error) || isSigning}
>
{isSigning ? (
<span className="loading loading-dots loading-sm"></span>
) : (
'Next: Token Metadata'
<button
type="submit"
className="w-full mt-4 btn px-5 py-2.5 sm:py-3.5 btn-primary"
disabled={!isValid || !dirty || isSigning}
>
{isSigning ? (
<span className="loading loading-dots loading-sm"></span>
) : (
'Next: Token Metadata'
)}
</button>
</Form>
)}
</button>
</Formik>
<div className="flex space-x-3 ga-4 mt-6">
<Link href={'/factory'} legacyBehavior>
<button className=" btn btn-neutral py-2.5 sm:py-3.5 w-1/2 ">
Expand Down
Loading

0 comments on commit 15eb0c2

Please sign in to comment.