Files
hossein-por-shop/frontend/components/global/FileInput.vue
T
2025-02-27 20:47:37 +03:30

153 lines
4.2 KiB
Vue

<script setup lang="ts">
// imports
import { useToast } from "~/composables/global/useToast";
// types
type Props = {
modelValue: ServerFile[];
loading?: boolean;
};
type Emits = {
"update:modelValue": [value: any];
change: [value: File];
};
// props
const props = defineProps<Props>();
const { modelValue } = toRefs(props);
// emits
const emit = defineEmits<Emits>();
// state
const { addToast } = useToast();
const dropZoneRef = ref<HTMLDivElement>();
const fileLimit = 1024 * 1024 * 2;
// methods
const onDrop = (files: File[] | null) => {
if (modelValue.value.length < 3) {
files?.forEach((file, index) => {
if (file.size > fileLimit) {
files.splice(index, 1);
addToast({
message: "حداکثر حجم فایل 2 مگابایت می باشد",
options: {
status: "error",
},
});
}
});
if (files.length > 3) {
emit("update:modelValue", [...files.slice(0, 3)]);
} else {
if (modelValue.value.length + files.length <= 3) {
files?.forEach((item) => {
emit("change", item);
resetFileDialog();
});
} else {
addToast({
message: `مجاز به آپلود ${
3 - modelValue.value.length
} فایل دیگر هستید`,
options: {
status: "error",
},
});
}
}
} else {
addToast({
message: "محدودیت تعداد را رعایت کنید",
options: {
status: "error",
},
});
}
};
const { isOverDropZone } = useDropZone(dropZoneRef, {
onDrop,
dataTypes: ["image/jpeg", "image/png", "image/jpg"],
});
const {
open: openDialog,
onChange,
reset: resetFileDialog,
} = useFileDialog({
accept: "image/*",
directory: false,
});
onChange((files: any) => {
let arr: File[] = [];
Object.keys(files).forEach((_, index) => {
arr.push(files[index]);
});
onDrop(arr);
});
const removeAttachment = (id: number) => {
let target = modelValue.value.findIndex((i) => i.id == id);
const clone = [...modelValue.value];
clone.splice(target, 1);
emit("update:modelValue", clone);
};
</script>
<template>
<div class="flex flex-col w-full h-max gap-5 pt-8">
<div
ref="dropZoneRef"
@click="openDialog"
class="bg-slate-50 relative flex-col-center w-full transition-all text-black/50 gap-3 h-[20rem] border border-dashed rounded-xl cursor-pointer select-none"
:class="{
'border-black': isOverDropZone,
' border-slate-300': !isOverDropZone,
'pointer-events-none': loading,
}"
>
<Icon
:name="
loading
? 'svg-spinners:ring-resize'
: 'bi:file-earmark-arrow-down'
"
size="32"
:class="loading ? '' : ''"
/>
<p class="font-bold text-dynamic-primary text-sm lg:text-[1rem]">
برای آپلود کلیک کنید یا فایل خود را اینجا بیاندازید
</p>
<p class="text-xs font-semibold">فرمت مجاز : jpg, png, jpeg</p>
<p class="text-xs font-semibold">تعداد فایل مجاز : 3 عدد</p>
<p class="text-xs font-semibold">حداکثر حجم فایل : 2 مگابایت</p>
</div>
<ul
v-for="(item, index) in modelValue"
:key="index"
v-auto-animate
class="flex flex-row-reverse items-center justify-between w-full px-2 animate__animated animate__fadeIn"
>
<NewAttachment
:id="item.id"
:size="item.size"
:name="item.name"
@delete="removeAttachment"
/>
</ul>
</div>
</template>