Your IP : 216.73.217.77


Current Path : /home/users/unlimited/www/whatsapp-crm/resources/js/Components/
Upload File :
Current File : /home/users/unlimited/www/whatsapp-crm/resources/js/Components/ContactImportModal.vue

<script setup>
    import { computed, ref, watch } from 'vue';
    import { Link, router, usePage } from "@inertiajs/vue3";
    import Modal from '@/Components/Modal.vue';
    import { trans } from 'laravel-vue-i18n';

    const props = defineProps(['type', 'modelValue']);
    const emit = defineEmits(['update:modelValue']);
    const flashResponse = computed(() => usePage().props.flash.status);
    
    const modalLabel = props.type === 'contact' ? trans('Import contacts') : trans('Import contact groups');
    const isOpenModal = ref(props.modelValue);
    const fileName = ref(null);
    const progressStatus = ref(null);

    watch(() => props.modelValue, (newValue) => {
        isOpenModal.value = newValue;
    });
    
    const handleFileUpload = (event) => {
        event.preventDefault();
        const file = event.target.files[0];
        uploadFile(file);  
    }

    const handleDrop = (event) => {
        event.preventDefault();
        const file = event.dataTransfer.files[0];
        uploadFile(file);  
    };

    function uploadFile(file){
        if (!['text/csv', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'].includes(file.type)) {
            alert(trans('please select a CSV or XLSX file'));
            return;
        }

        fileName.value = file.name;

        const formData = new FormData();
        formData.append('file', file);

        // Use Inertia router to send the POST request
        router.post(props.type === 'contact' ? '/contacts/import' : '/contact-groups/import', formData, {
            forceFormData: true,
            onProgress: event => {
                progressStatus.value = 'pending';
            },
            onSuccess: () => {
                progressStatus.value = 'complete';
            },
            onError: (errors) => {
                progressStatus.value = null;
            }
        });
    }

    function closeModal(){
        isOpenModal.value = false;
        emit('update:modelValue', false);
        setTimeout(() => {
            progressStatus.value = null;
        }, 500);
    }
</script>
<template>
    <!-- Import Modal-->
    <Modal :label="modalLabel" :isOpen="isOpenModal">
        <div v-if="type === 'contact'" class="text-sm text-slate-600">{{ $t('Upload a csv/xlsx to import your contact data. For the phone field ensure that you start with the contact\'s country code.') }}</div>
        <div v-else class="text-sm text-slate-600">{{ $t('Upload a csv/xlsx to import your contact groups data.') }}</div>
        <div class="text-sm text-slate-600 underline flex mt-4 mb-6">
            <a :href="type === 'contact' ? '/contacts.xlsx' : '/contact-groups.xlsx'">{{ $t('Click here to download sample template') }}</a>
        </div>
        <div class="max-w-md w-full gap-y-8">
            <div class="space-y-6">
                <div v-if="progressStatus == null || progressStatus == 'complete'" @dragover.prevent @drop="handleDrop" class="flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md">
                    <input type="file" class="sr-only" accept=".csv,.xlsx" ref="fileInput" id="file-upload" @change="handleFileUpload($event)"/>
                    <div class="text-center">
                        <div>
                            <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none"><path fill="currentColor" d="m15.393 4.054l-.502.557l.502-.557Zm3.959 3.563l-.502.557l.502-.557Zm2.302 2.537l-.685.305l.685-.305ZM3.172 20.828l.53-.53l-.53.53Zm17.656 0l-.53-.53l.53.53ZM14 21.25h-4v1.5h4v-1.5ZM2.75 14v-4h-1.5v4h2.5Zm18.5-.437V14h2.5v-.437h-1.5ZM14.891 4.61l3.959 3.563l1.003-1.115l-3.958-3.563l-1.004 1.115Zm7.859 8.952c0-1.689.015-2.758-.41-3.714l-1.371.61c.266.598.281 1.283.281 3.104h2.5Zm-3.9-5.389c1.353 1.218 1.853 1.688 2.119 2.285l1.37-.61c-.426-.957-1.23-1.66-2.486-2.79L18.85 8.174ZM10.03 2.75c1.582 0 2.179.012 2.71.216l.538-1.4c-.852-.328-1.78-.316-3.248-.316v1.5Zm5.865.746c-1.086-.977-1.765-1.604-2.617-1.93l-.537 1.4c.532.204.98.592 2.15 1.645l1.004-1.115ZM10 21.25c-1.907 0-3.261-.002-4.29-.14c-1.005-.135-1.585-.389-2.008-.812l-1.06 1.06c.748.75 1.697 1.081 2.869 1.239c1.15.155 2.625.153 4.489.153v-1.5ZM1.25 14c0 1.864-.002 3.338.153 4.489c.158 1.172.49 2.121 1.238 2.87l1.06-1.06c-.422-.424-.676-1.004-.811-2.01c-.138-1.027-.14-2.382-.14-4.289h-1.5ZM14 22.75c1.864 0 3.338.002 4.489-.153c1.172-.158 2.121-.49 2.87-1.238l-1.06-1.06c-.424.422-1.004.676-2.01.811c-1.027.138-2.382.14-4.289.14v1.5ZM21.25 14c0 1.907-.002 3.262-.14 4.29c-.135 1.005-.389 1.585-.812 2.008l1.06 1.06c.75-.748 1.081-1.697 1.239-2.869c.155-1.15.153-2.625.153-4.489h-1.5Zm-18.5-4c0-1.907.002-3.261.14-4.29c.135-1.005.389-1.585.812-2.008l-1.06-1.06c-.75.748-1.081 1.697-1.239 2.869C1.248 6.661 1.25 8.136 1.25 10h2.5Zm7.28-8.75c-1.875 0-3.356-.002-4.511.153c-1.177.158-2.129.49-2.878 1.238l1.06 1.06c.424-.422 1.005-.676 2.017-.811c1.033-.138 2.395-.14 4.312-.14v-1.5Z"/><path stroke="currentColor" stroke-width="1.5" d="M13 2.5V5c0 2.357 0 3.536.732 4.268C14.464 10 15.643 10 18 10h4"/></g></svg>
                            <div class="flex text-sm text-gray-600">
                                <label for="file-upload" class="relative cursor-pointer bg-white rounded-md font-medium text-indigo-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500">
                                    <span>{{ $t('Click to upload a file') }}</span>
                                </label>
                                <p class="pl-1">{{ $t('Or drag and drop') }}</p>
                            </div>
                            <p class="text-xs text-gray-500">{{ $t('CSV/XLSX files only') }}</p>
                        </div>
                    </div>
                </div>
                <div v-else class="flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md">
                    <div>
                        <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24"><path fill="none" stroke="black" stroke-dasharray="15" stroke-dashoffset="15" stroke-linecap="round" stroke-width="2" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></svg>
                        <div class="text-center mb-2 text-sm text-gray-500">Upload In Progress</div>
                        <div class="rounded-md p-1 bg-slate-50 text-center text-sm">{{ fileName }}</div>
                    </div>
                </div>
                <div class="mt-4">
                    <div class="mt-2" v-if="progressStatus == 'complete'">
                        <div v-if="flashResponse.successfulImports" class="bg-green-50 px-2 py-2 flex rounded-md justify-between items-center mb-1">
                            <div class="mt-1 text-sm">
                                <div class="text-green-800 flex items-center gap-x-2">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M14.25 8.75c-.5 2.5-2.385 4.854-5.03 5.38A6.25 6.25 0 0 1 3.373 3.798C5.187 1.8 8.25 1.25 10.75 2.25"/><path d="m5.75 7.75l2.5 2.5l6-6.5"/></g></svg>
                                    {{ flashResponse.successfulImports + '/' + flashResponse.totalImports }} {{ $t('rows added successfully!') }}
                                </div>
                            </div>
                        </div>
                        <div v-if="flashResponse.failedNames" class="bg-red-50 px-2 py-2 flex rounded-md justify-between items-center mb-1">
                            <div class="mt-1 text-sm">
                                <div class="text-red-600 flex items-center gap-x-2">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M15.71 8.29a1 1 0 0 0-1.42 0L12 10.59l-2.29-2.3a1 1 0 0 0-1.42 1.42l2.3 2.29l-2.3 2.29a1 1 0 0 0 0 1.42a1 1 0 0 0 1.42 0l2.29-2.3l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42L13.41 12l2.3-2.29a1 1 0 0 0 0-1.42m3.36-3.36A10 10 0 1 0 4.93 19.07A10 10 0 1 0 19.07 4.93m-1.41 12.73A8 8 0 1 1 20 12a7.95 7.95 0 0 1-2.34 5.66"/></svg>
                                    {{ flashResponse.failedNames }} rows without first name
                                </div>
                            </div>
                        </div>
                        <div v-if="flashResponse.failedDuplicates" class="bg-red-50 px-2 py-2 flex rounded-md justify-between items-center mb-1">
                            <div class="mt-1 text-sm">
                                <div class="text-red-600 flex items-center gap-x-2">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M15.71 8.29a1 1 0 0 0-1.42 0L12 10.59l-2.29-2.3a1 1 0 0 0-1.42 1.42l2.3 2.29l-2.3 2.29a1 1 0 0 0 0 1.42a1 1 0 0 0 1.42 0l2.29-2.3l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42L13.41 12l2.3-2.29a1 1 0 0 0 0-1.42m3.36-3.36A10 10 0 1 0 4.93 19.07A10 10 0 1 0 19.07 4.93m-1.41 12.73A8 8 0 1 1 20 12a7.95 7.95 0 0 1-2.34 5.66"/></svg>
                                    {{ flashResponse.failedDuplicates }} duplicates found
                                </div>
                            </div>
                        </div>
                        <div v-if="flashResponse.failedFormats" class="bg-red-50 px-2 py-2 flex rounded-md justify-between items-center mb-1">
                            <div class="mt-1 text-sm">
                                <div class="text-red-600 flex items-center gap-x-2">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M15.71 8.29a1 1 0 0 0-1.42 0L12 10.59l-2.29-2.3a1 1 0 0 0-1.42 1.42l2.3 2.29l-2.3 2.29a1 1 0 0 0 0 1.42a1 1 0 0 0 1.42 0l2.29-2.3l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42L13.41 12l2.3-2.29a1 1 0 0 0 0-1.42m3.36-3.36A10 10 0 1 0 4.93 19.07A10 10 0 1 0 19.07 4.93m-1.41 12.73A8 8 0 1 1 20 12a7.95 7.95 0 0 1-2.34 5.66"/></svg>
                                    {{ flashResponse.failedFormats }} formatting issues found
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div v-if="progressStatus == null || progressStatus == 'complete'" class="mt-5">
            <div class="flex justify-center mt-2 w-full">
                <button type="button" @click="closeModal()" class="w-full inline-flex justify-center rounded-md border border-transparent bg-primary px-4 py-2 text-sm text-white hover:text-slate-500 hover:bg-slate-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">{{ $t('Close') }}</button>
            </div>
        </div>
    </Modal>
</template>