153 lines
4.2 KiB
Vue
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>
|