refactor(material): modify validation uom and item

This commit is contained in:
riefive
2025-09-04 16:21:10 +07:00
parent 21d087e496
commit ffa4a7d191
5 changed files with 41 additions and 27 deletions
+16 -14
View File
@@ -11,6 +11,7 @@ import Label from '~/components/pub/custom-ui/form/label.vue'
interface Props {
isLoading: boolean
schema: z.ZodSchema<any>
uoms: any[]
items: any[]
}
@@ -20,11 +21,13 @@ const emit = defineEmits<{
submit: [data: any]
}>()
const { handleSubmit, defineField, errors, meta } = useForm({
const { handleSubmit, defineField, errors } = useForm({
validationSchema: toTypedSchema(props.schema),
initialValues: {
code: '',
name: '',
uom_code: '',
item_id: '',
stock: 0,
} as Partial<MaterialFormData>,
})
@@ -36,7 +39,6 @@ const [item, itemAttrs] = defineField('item_id')
const [stock, stockAttrs] = defineField('stock')
const onSubmit = handleSubmit(async (values) => {
console.log(errors)
try {
emit('submit', values)
} catch (error) {
@@ -77,30 +79,32 @@ const onSubmit = handleSubmit(async (values) => {
<Label for="uom">Satuan</Label>
<Select
id="uom"
:items="items"
icon-name="i-lucide-chevron-down"
placeholder="Pilih satuan"
v-model="uom"
v-bind="uomAttrs"
:items="uoms"
:disabled="isLoading"
:class="{ 'border-red-500': errors.uom }"
:class="{ 'border-red-500': errors.uom_code }"
/>
<span v-if="errors.uom" class="text-sm text-red-500">
{{ errors.uom }}
<span v-if="errors.uom_code" class="text-sm text-red-500">
{{ errors.uom_code }}
</span>
</div>
<div class="grid gap-2">
<Label for="item">Item</Label>
<Select
id="item"
:items="items"
icon-name="i-lucide-chevron-down"
placeholder="Pilih item"
v-model="item"
v-bind="itemAttrs"
:items="items"
:disabled="isLoading"
:class="{ 'border-red-500': errors.item }"
:class="{ 'border-red-500': errors.item_id }"
/>
<span v-if="errors.item" class="text-sm text-red-500">
{{ errors.uom }}
<span v-if="errors.item_id" class="text-sm text-red-500">
{{ errors.item_id }}
</span>
</div>
<div class="grid gap-2">
@@ -117,10 +121,8 @@ const onSubmit = handleSubmit(async (values) => {
{{ errors.stock }}
</span>
</div>
<div class="flex justify-end gap-2 my-2 py-2">
<Button variant="secondary" class="w-[120px]" @click="emit('back')">
Kembali
</Button>
<div class="my-2 flex justify-end gap-2 py-2">
<Button variant="secondary" class="w-[120px]" @click="emit('back')"> Kembali </Button>
<Button type="submit" class="w-[120px]">
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
Simpan
+17 -6
View File
@@ -1,13 +1,17 @@
<script setup lang="ts">
// types
import { MaterialSchema, type MaterialFormData } from '~/schemas/material'
// components
import Action from '~/components/pub/custom-ui/nav-footer/ba-dr-su.vue'
const isLoading = ref(false)
const uoms = [
{ value: 'uom-1', label: 'Satuan 1' },
{ value: 'uom-2', label: 'Satuan 2' },
{ value: 'uom-3', label: 'Satuan 3' },
]
const items = [
{ value: 'item1', label: 'Item 1' },
{ value: 'item2', label: 'Item 2' },
{ value: 'item-1', label: 'Item 1' },
{ value: 'item-2', label: 'Item 2' },
{ value: 'item-3', label: 'Item 3' },
]
function onBack() {
@@ -15,7 +19,7 @@ function onBack() {
}
async function onSubmit(data: MaterialFormData) {
console.log(data);
console.log(data)
}
</script>
@@ -24,5 +28,12 @@ async function onSubmit(data: MaterialFormData) {
<Icon name="i-lucide-panel-bottom" class="me-2" />
<span class="font-semibold">Tambah</span> Perlengkapan (BMHP)
</div>
<AppMaterialEntryForm :is-loading="isLoading" :schema="MaterialSchema" :items="items" @back="onBack" @submit="onSubmit" />
<AppMaterialEntryForm
:is-loading="isLoading"
:schema="MaterialSchema"
:uoms="uoms"
:items="items"
@back="onBack"
@submit="onSubmit"
/>
</template>
+2 -1
View File
@@ -19,6 +19,7 @@ interface Item {
const props = defineProps<
SelectRootProps & {
items: Item[]
iconName?: string
placeholder?: string
label?: string
separator?: boolean
@@ -31,7 +32,7 @@ const forwarded = useForwardPropsEmits(props, emits)
<template>
<SelectRoot v-bind="forwarded">
<SelectTrigger class="">
<SelectTrigger :icon-name="iconName" class="flex justify-between items-center">
<SelectValue :placeholder="placeholder" />
</SelectTrigger>
@@ -5,15 +5,15 @@ import { SelectIcon, SelectTrigger, useForwardProps } from 'radix-vue'
import { computed } from 'vue'
import { cn } from '~/lib/utils'
const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'], iconName?: string }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
const iconName = computed(() => props.iconName || 'i-radix-icons-caret-sort')
</script>
<template>
@@ -28,7 +28,7 @@ const forwardedProps = useForwardProps(delegatedProps)
>
<slot />
<SelectIcon as-child>
<Icon name="i-radix-icons-caret-sort" class="h-4 w-4 opacity-50" />
<Icon :name="iconName" class="h-4 w-4 opacity-50" />
</SelectIcon>
</SelectTrigger>
</template>
+3 -3
View File
@@ -3,9 +3,9 @@ import { z } from 'zod'
const schema = z.object({
code: z.string({ required_error: 'Kode harus diisi' }).min(1, 'Kode minimum 1 karakter'),
name: z.string({ required_error: 'Nama harus diisi' }).min(1, 'Nama minimum 1 karakter'),
uom_code: z.string({ required_error: 'Kode unit harus diisi' }),
item_id: z.string({ required_error: 'Tipe harus diisi' }),
stock: z.preprocess((val) => Number(val), z.number({ invalid_type_error: 'Stok harus berupa angka' }).min(1)),
uom_code: z.string({ required_error: 'Kode unit harus diisi' }).min(1, 'Kode unit harus diisi'),
item_id: z.string({ required_error: 'Tipe harus diisi' }).min(1, 'Tipe harus diisi'),
stock: z.preprocess((val) => Number(val), z.number({ invalid_type_error: 'Stok harus berupa angka' }).min(1, 'Stok harus lebih besar dari 0')),
})
type formData = z.infer<typeof schema>