refactor: fix validation for add gacha roll item

- Pisahkan type dan schema untuk gacha roll item
- Perbaiki validasi gacha roll item
- Parsing angka pada component ControlledInputField
- Update type number untuk component Input dan InputField
This commit is contained in:
Hafid Nur
2025-04-05 07:39:57 +07:00
parent 885d156833
commit 3958ae1098
8 changed files with 58 additions and 27 deletions
@@ -78,7 +78,8 @@ const StepOne = ({ nextStep }: IStepOneProps) => {
control={form.control}
label="Quantity"
name="quantity"
type="text"
type="number"
min={1}
placeholder="Masukkan Kuantitas Item"
size="lg"
className="w-full"
@@ -87,8 +88,12 @@ const StepOne = ({ nextStep }: IStepOneProps) => {
control={form.control}
label="Chance Rate"
name="chanceRate"
type="text"
placeholder="Masukkan Chance Rate (0.1 - 1)"
type="number"
value={0.1}
min={0.1}
step={0.1}
max={1}
placeholder="Masukkan Chance Rate (0,1 - 1)"
size="lg"
className="w-full"
/>
@@ -1,27 +1,13 @@
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
const addItemSchema = z.object({
itemName: z.string().min(1, 'Item name is required'),
quantity: z.string().min(1, 'Quantity is required'),
chanceRate: z
.string()
.min(1, 'Chance rate is required')
.refine(
(val) => {
const num = parseFloat(val);
return num >= 0.1 && num <= 1;
},
{ message: 'Chance rate must be between 0.1 and 1' }
),
});
type TAddItemForm = z.infer<typeof addItemSchema>;
import {
gachaRollItemSchema,
TGachaRollItem
} from '@imphnen-frontend-service/service';
export const useAddItem = (nextStep: () => void) => {
const form = useForm<TAddItemForm>({
resolver: zodResolver(addItemSchema),
const form = useForm<TGachaRollItem>({
resolver: zodResolver(gachaRollItemSchema),
mode: 'all',
});
+23
View File
@@ -0,0 +1,23 @@
import { z } from 'zod';
export const gachaRollItemSchema = z.object({
itemName: z
.string({
required_error: 'Nama item tidak boleh kosong',
invalid_type_error: 'Nama item harus berupa string',
})
.min(1, 'Nama item tidak boleh kosong'),
quantity: z
.number({
required_error: 'Quantity tidak boleh kosong',
invalid_type_error: 'Quantity harus berupa angka',
})
.min(1, 'Quantity paling sedikit adalah 1'),
chanceRate: z
.number({
required_error: 'Chance rate tidak boleh kosong',
invalid_type_error: 'Chance rate harus berupa angka',
})
.min(0.1, 'Chance rate paling sedikit adalah 0,1')
.max(1, 'Chance rate paling banyak adalah 1'),
});
+1
View File
@@ -1 +1,2 @@
export * from './auth';
export * from './gacha';
+5 -1
View File
@@ -1 +1,5 @@
export {};
export type TGachaRollItem = {
itemName: string;
quantity: number;
chanceRate: number;
};
+1 -1
View File
@@ -9,7 +9,7 @@ import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons'; // Import
import { cn } from '@imphnen-frontend-service/utils';
import { Button } from '../button';
type TInputType = 'text' | 'email' | 'password' | 'file';
type TInputType = 'text' | 'email' | 'number' | 'password' | 'file';
type TInputSize = 'sm' | 'md' | 'lg';
type TInputProps = Omit<
@@ -7,7 +7,7 @@ import {
import { Input } from '../../atoms';
import { cn } from '@imphnen-frontend-service/utils';
export type TInputType = 'text' | 'email' | 'password' | 'file';
export type TInputType = 'text' | 'email' | 'number' | 'password' | 'file';
export type TInputSize = 'sm' | 'md' | 'lg';
export type TInputFieldProps = Omit<
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
@@ -15,7 +15,19 @@ export const ControlledInputField = <T extends FieldValues>(
props: TControlledInputFieldProps<T>
) => {
const { field, fieldState } = useController<T>(props);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value =
props.type === 'number' ? Number(e.target.value) : e.target.value;
field.onChange(value);
};
return (
<InputField error={fieldState.error?.message} {...{ ...props, ...field }} />
<InputField
error={fieldState.error?.message}
{...props}
{...field}
onChange={handleChange}
/>
);
};