Files

106 lines
2.6 KiB
Vue

<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { Input } from '~/components/pub/ui/input'
import { cn } from '~/lib/utils'
import * as DE from '~/components/pub/my-ui/doc-entry'
interface Props {
fieldName: string
label?: string
placeholder?: string
hint?: string
modelValue?: File | null
accept?: string[]
maxSizeMb?: number
errors?: FormErrors
class?: string
isRequired?: boolean
isDisabled?: boolean
icons?: string
}
const props = withDefaults(defineProps<Props>(), {
label: '',
placeholder: 'Choose file...',
maxSizeMb: 1,
isDisabled: false,
isRequired: false,
})
const emit = defineEmits<{
(e: 'update:modelValue', value: File | null): void
(e: 'fileSelected', file: File | null): void
}>()
const hintMsg = computed(() => {
if (props.hint) return props.hint
if (props.accept) {
return `${props.accept.map((ext) => '.' + ext.replace(/^\./, '')).join(', ')}, maksimal ${props.maxSizeMb} MB`
}
return 'Gunakan file yang sesuai'
})
async function onFileChange(event: Event, handleChange: (value: any) => void) {
const target = event.target as HTMLInputElement
const file = target.files?.[0]
if (!file) {
handleChange(null)
emit('update:modelValue', null)
emit('fileSelected', null)
return
}
// Validate file size
const maxSizeBytes = props.maxSizeMb * 1024 * 1024
if (file.size > maxSizeBytes) {
console.warn(`File size exceeds ${props.maxSizeMb}MB limit`)
handleChange(null)
emit('update:modelValue', null)
emit('fileSelected', null)
return
}
handleChange(file)
emit('update:modelValue', file)
emit('fileSelected', file)
}
</script>
<template>
<DE.Cell :class="class">
<DE.Label
v-if="label !== ''"
:label-for="fieldName"
:is-required="isRequired && !isDisabled"
>
{{ label }} ({{ hintMsg }})
</DE.Label>
<DE.Field
:id="fieldName"
:errors="errors"
>
<FormField
v-slot="{ componentField, handleChange }"
:name="fieldName"
>
<FormItem>
<FormControl class="flex flex-col">
<Input
:id="fieldName"
type="file"
:disabled="isDisabled"
v-bind="{ onBlur: componentField.onBlur }"
:placeholder="placeholder"
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
@change="onFileChange($event, handleChange)"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</DE.Field>
</DE.Cell>
</template>