Untitled

 avatar
unknown
javascript
a year ago
26 kB
3
Indexable
<template>
    <LayoutPage>
        <PageTitle :title-page="$t('catalog.title')" />
        <Alert 
            v-if="errorResponse" 
            type="danger" 
            :is-dismissible="true" 
            :text="responseMsg" 
            @handle-close="errorResponse = false"
            style="margin:-20px 0 -40px 0; z-index:1;"
        />
        <div v-if="generalLoading" class="d-flex justify-content-center align-items-center vh-100">
            <SpinnerLoading />
        </div>
        <div v-else :class="['card p-3', { 'block-section': errorResponse }]">
            <div class="card-body">
                <div class="row mb-3">
                    <div class="col-12 bg-soft-primary rounded py-3 px-4 mb-5">
                        <template v-if="showCVComponent">
                            <template v-if="isVerifiedNumberSuccess">
                                <div class="container pt-3 pb-5">
                                     <div class="row justify-content-center">
                                        <div class="col-12 col-md-6 text-center">
                                            <i class="fas fa-check fa-3x text-success"></i>
                                            <p class="fw-bold mt-4">
                                                {{ $t('verifiedNumber.verifiedTitle', { value: verifiedResponse.phoneNumber }) }}
                                            </p>
                                            <p class="text-muted">
                                                {{ $t('verifiedNumber.verifiedMsg') }}
                                            </p>
                                            <p>
                                                <button 
                                                    type="button" 
                                                    class="btn btn-deep px-3" 
                                                    @click="initCFComponent"
                                                >
                                                    {{ $t('buttons.accept')}}
                                                </button>
                                            </p>
                                        </div>
                                    </div>
                                </div>
                            </template>
                            <template v-else-if="isVerifiedNumberError">
                                <div class="container pt-3 pb-5">
                                     <div class="row justify-content-center">
                                        <div class="col-12 col-md-6 text-center">
                                            <i class="far fa-times-circle fa-3x text-danger"></i>
                                            <p class="fw-bold mt-4">
                                                {{ $t('verifiedNumber.notVerifiedTitle', { value: verifiedResponse.phoneNumber }) }}
                                            </p>
                                            <p class="text-muted" v-html="$t('verifiedNumber.notVerifiedMsg', { value: 'support@flynode.mx' })"></p>
                                            <p>
                                                <button 
                                                    type="button" 
                                                    class="btn btn-deep px-3" 
                                                    @click="initCFComponent"
                                                >
                                                    {{ $t('buttons.accept')}}
                                                </button>
                                            </p>
                                        </div>
                                    </div>
                                </div>
                            </template>
                            <template v-else>
                                <CodeVerification 
                                    :statusResponse="verifiedResponse"
                                    @onAlert="triggerModal"
                                    :label="verifiedNumberLabels"
                                    :submitCode="verifyCode"
                                    v-model="verificationCode"
                                    :sendNew="sendNewCode"
                                />
                            </template>
                        </template>
                        <template v-else>
                            <h5 class="mb-3">{{$t('verifiedNumber.verifyNewNumber')}}</h5>
                            <div class="row gx-5">
                                <div class="col-md-3 mb-5">
                                    <Multiselect
                                        v-model="verifyModel.country_code_id"
                                        :placeholder="$t('selectOption')"
                                        track-by="country_name"
                                        valueProp="country_code"
                                        label="country_name"
                                        :options="countryCodes"
                                        @open="initGetCountryCodes"
                                        @change="handleChange"
                                        :searchable="true"
                                        :noOptionsText="$t('loading')"
                                        :class="['multiselect-custom', { 'border-danger': errors.country_code_id }]"
                                    >
                                        <template v-slot:singlelabel="{ value }">
                                            <div class="multiselect-single-label">
                                                <img class="option-image" :src="`${urlAssets}/${value.path_to_flag}`" width="40" height="24" style="width:40px; height:24px;"> ({{value.country_code}}) {{ value.country_name }}
                                            </div>
                                        </template>
                                        <template v-slot:option="{ option }">
                                            <img class="option-image" :src="`${urlAssets}/${option.path_to_flag}`" width="40" height="24" style="width:40px; height:24px;">({{option.country_code}} ) {{ option.country_name }}
                                        </template>
                                    </Multiselect>
                                    <div v-if="errors.country_code_id" class="invalid-feedback d-block">{{errors.country_code_id}}</div>
                                </div>
                                <div v-if="togglePhoneType" class="col-md-4 mb-5">
                                    <select :class="['form-select bg-white', { 'is-invalid': errors.type }]" v-model="verifyModel.type">
                                        <option value="null" disabled>{{$t('selectOption')}}</option>
                                        <option value="mobile">{{$t('verifiedNumber.mobile')}}</option>
                                        <option value="permanent">{{$t('verifiedNumber.permanent')}}</option>
                                    </select>
                                    <div v-if="errors.type" class="invalid-feedback">{{errors.type}}</div>
                                </div>
                                <div class="col-md-4 mb-5">
                                    <input type="text" :class="['form-control bg-white', { 'is-invalid': errors.phone_number }]" :placeholder="$t('verifiedNumber.addPhoneNumber')" v-model="verifyModel.phone_number"/>
                                    <div v-if="errors.phone_number" class="invalid-feedback">{{errors.phone_number}}</div>
                                </div>
                            </div>
                            <div class="text-center">
                                <button type="button" class="btn btn-orange text-white fw-bold" 
                                    @click="submitVerificationCode"
                                    :disabled="isSubmitLoading"
                                >
                                    <template v-if="isSubmitLoading">
                                        <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                                        <span class="visually-hidden">Loading...</span>
                                    </template>
                                    {{$t('verifiedNumber.sendVerificationCode')}}</button>
                                <div class="d-inline ms-2">
                                    <CustomTooltip
                                        placement="right"
                                        data-bs-html="true"
                                        :title="`<div>${$t('verifiedNumber.sendTooltip')}</div>`"
                                    />
                                </div>
                            </div>
                        </template>
                    </div>
                    <div class="col-md-9">
                        <h5 class="fw-bold">{{$t('verifiedNumber.title')}}</h5>
                    </div>
                    <div class="col-md-3 text-end d-none">
                        <router-link
                            class="btn btn-orange text-white fw-bold px-4"
                            :to="{name: 'NewVerifiedNumbers'}"
                        >
                            <i class="fas fa-plus fa-sm"></i>
                            {{$t('verifiedNumber.newOption')}}
                        </router-link>
                    </div>
                </div>
                <DataTable
                    :url="NUMBERS_URL"
                    :columns="tableColumnsName"
                    :search-input="true"
                    @emitData="emitTableData"
                >
                    <tbody>
                        <tr v-if="data.length === 0">
                            {{$t('table.noResultsFound')}}
                        </tr>
                        <tr v-else v-for="(item, key) in data" :key="key" class="text-center">
                            <td>{{ item.id }}</td>
                            <td>{{ item.number }}</td>
                            <td>{{ item.type }}</td>
                            <td>{{ item.country_name }}</td>
                            <td> 
                               <CBadge :colorClass="statusClass(item.status_code)">
                                    {{$t(`status.${item.status}`)}}
                               </CBadge>
                            </td>
                            <td class="d-flexjustify-content-center">
                                <template v-if="item.block_edit">
                                    <span class="btn btn-primary btn-sm mx-1" style="cursor:default;">
                                        <i class="fas fa-lock"></i>
                                    </span>
                                </template>
                                <template v-else>
                                    <router-link class="btn btn-primary btn-sm mx-1 d-none" :to="{name: 'EditVerifiedNumbers', params: {id: item.id} }">
                                        <i class="fas fa-pen"></i>
                                    </router-link>
                                    <button class="btn btn-primary btn-sm mx-1"  @click="deleteRow(item)">
                                        <i class="fas fa-trash"></i>
                                    </button>
                                </template>
                            </td>
                        </tr>
                    </tbody>
                </DataTable>
            </div>
        </div>
    </LayoutPage>
</template>

<script setup>
    import LayoutPage from '@/components/LayoutPage.vue';
    import PageTitle from '@/components/PageTitle.vue';
    import Alert from '@/components/Alert.vue';
    import SingleAccordion from  '@/components/SingleAccordion';
    import CustomTooltip from "@/components/CustomTooltip.vue";
    import flatPickr from 'vue-flatpickr-component';
    import Multiselect from '@vueform/multiselect';
    import CodeVerification from '@/components/CodeVerification.vue';
    import CBadge from '@/components/CBadge.vue';
    import Swal from 'sweetalert2';
    import DataTable from '@/components/organismos/DataTable';
    import i18n from "@/i18n";
    
    import { reactive, ref, onMounted } from 'vue';
    import {useRouter} from 'vue-router';
    import axios from 'axios';
    import { throwErrorMessage } from '@/composables/helper';
    import {filter} from '@/validators/catalogueSchema.js';
    import {getCountryCodes} from '@/composables/sip';
    import {verifySchema, verifiedNumbers} from '@/validators/verifyNumberSchema.js';

    const generalLoading = ref(false);//temporaly waiting for services
    const filterData = ref({});
    const filterErrors = ref({});
    const data = ref([]);
    const deleteSuccess = ref(false);
    const selectedStatus = ref({});
    const showCVComponent = ref(false);
    const isVerifiedNumberSuccess = ref(null),
          isVerifiedNumberError = ref(null);
    
    const status = ref([]);
    const errorResponse = ref(false);
    const responseMsg = ref('');
    const errors = ref({});
    const urlAssets = process.env.VUE_APP_ASSETS_URL;
    const togglePhoneType = ref(false);
    const verifiedResponse = reactive({
        status:true,
        statusName: "sending",
        phoneNumber: null
    });
    const countryCodes = ref([]);
    const verifyModel = ref({});
    const isSubmitLoading = ref(false);

    const router = useRouter();

    const NUMBERS_URL = ref(`${process.env.VUE_APP_API_URL}/api/dids/status/`);

    const tableColumnsName = ref([
        { label: '#', name: 'id', sort: false },
        { label: i18n.global.t('table.number'), name: 'number', sort: false },
        { label: i18n.global.t('table.type'), name: 'type', sort: true },
        { label: i18n.global.t('country'), name: 'country', sort: true },
        { label: i18n.global.t('table.status'), name: 'status', sort: true },
        { label: i18n.global.t('table.actions'), name: 'actions', sort: false },
    ]);

    const attempts = ref(3);

    const verificationCode = ref("");

    const verifiedNumberLabels =  reactive({
        titleLabel : i18n.global.t('verifiedNumber.component.titleLabel'),
        instructionLabel: i18n.global.t('verifiedNumber.component.instructionLabel'),
        verificationCodeLabel: i18n.global.t('verifiedNumber.component.verificationCodeLabel'),
        verifyButtonLabel: i18n.global.t('verifiedNumber.component.verifyButtonLabel'),
        cancelButtonLabel: i18n.global.t('verifiedNumber.component.cancelButtonLabel'),
        codeNotReceivedLabel: i18n.global.t('verifiedNumber.component.codeNotReceivedLabel'),
        clickHereLabel: i18n.global.t('verifiedNumber.component.clickHereLabel'),
        codeSentLabel: i18n.global.t('verifiedNumber.component.codeSentLabel'),
        sendNewCodeLabel: i18n.global.t('verifiedNumber.component.sendNewCodeLabel'),
        attemptsLabel: i18n.global.t('verifiedNumber.component.attemptsLabel', { attempts: attempts.value})
    });

    const emitTableData = (source) => data.value = source;

    const getStatus = async() => {
        try {
            const { data: { data: {payload}  } } = await axios.get(`${process.env.VUE_APP_API_URL}/api/status/`);
            status.value = payload.filter( e => (e.status == 'inactive' || e.status == 'active' || e.status == 'eliminated' ?  e : null));
        } catch (error) {
            console.log(error)
        }
    }

    const statusClass = (val) => {
        return val == 1 ? 'bg-success'
            : val == 0 ? 'bg-danger'
            : 'bg-secondary';
    };

    const handleChange = (option) => {
        if(option && option == 52) {
            return togglePhoneType.value = false;
        }
        if(option && option != 52) return togglePhoneType.value = true;
    }

    const filterDataTable = async() => {
        try {
            filterErrors.value = {};
            await filter.validate( filterData.value, { abortEarly: false });
            DIDSTATUS_URL.value = `${process.env.VUE_APP_API_URL}/api/dids/status/?date_from=${filterData.value.startDate} 00:00:00&date_to=${filterData.value.endDate} 23:59:59&filter_key=status&filter_key_value=${filterData.value.status}`;
        } catch (error) {
            console.log(error);
            if(error?.name == 'ValidationError'){
                error.inner.forEach((err) => {
                    filterErrors.value = { ...filterErrors.value, [err.path]: i18n.global.t(err.message) };
                });
            }else{
                const errorMsg = throwErrorMessage(error);
                errorResponse.value = true;
                responseMsg.value = errorMsg;
            }
        }
    };

    const deleteRow = async(obj) => {
        const {id,status_name} = obj;

        Swal.fire({
            html: `
                <i class="fas fa-times-circle fa-3x text-danger mt-4 mb-2"></i>
                <p class="text-muted fw-bold mt-3 mb-2">${i18n.global.t('deleteQuestion', { value: status_name })}</p>`,
            showCancelButton: true,
            cancelButtonText: i18n.global.t('buttons.cancel'),
            confirmButtonText: i18n.global.t('buttons.accept'),
            showCloseButton: true,
            reverseButtons: true,
            customClass: {
                cancelButton: 'btn btn-soft-secondary fw-bold px-5 mx-3',
                confirmButton: 'btn btn-primary fw-bold px-5 mx-3',
                htmlContainer: 'container fs-6',
                validationMessage: 'bg-soft-danger'
            },
            buttonsStyling: false,
            preConfirm: async() => {
                try {
                    const response = await axios.delete(`${process.env.VUE_APP_API_URL}/api/dids/status/${id}`);
                    deleteSuccess.value = true;
                } catch (error) {
                    console.log(error);
                    Swal.showValidationMessage(
                        `Request failed: ${error}`
                    )
                }
            }
        }).then((result) => {
            if (result.isConfirmed) {
                Swal.fire({
                    html: `
                        <i class="fas fa-check-circle fa-3x text-success mt-4 mb-2"></i>
                        <p class="text-muted fw-bold mt-3 mb-2">${i18n.global.t('deleteSuccessMsg')}</p>`,
                    confirmButtonText: i18n.global.t('buttons.exit'),
                    showCloseButton: true,
                    customClass: {
                        confirmButton: 'btn btn-soft-secondary fw-bold px-5 mx-3',
                        htmlContainer: 'container fs-6',
                    },
                    buttonsStyling: false
                }).then((result) => {
                    if (result.isDismissed || result.isConfirmed) {
                        router.go();
                    }
                })
            }
        })
    }

    const triggerModal = () => {
        Swal.fire({
            iconHtml: '<i class="far fa-times-circle text-danger"></i>',
            html: `
                <h5 class="text-danger text-center">${i18n.global.t('verifiedNumber.noConnectionTitle')}</h5>
                <p class="text-secondary text-start fs-6 mt-3 fst-italic mb-0">${i18n.global.t('verifiedNumber.noConnectionMsg')}</p>`,
            showCancelButton: true,
            cancelButtonText: i18n.global.t('buttons.cancel'),
            confirmButtonText: i18n.global.t('buttons.call'),
            showCloseButton: false,
            reverseButtons: true,
            allowOutsideClick: false,
            customClass: {
                icon: 'border-0',
                cancelButton: 'btn btn-secondary fw-bold w-150px mx-3',
                confirmButton: 'btn btn-primary fw-bold w-150px mx-3',
                actions: '',
                validationMessage: 'bg-soft-danger',
                htmlContainer: 'mt-0',
            },
            buttonsStyling: false,
            preConfirm: async() => {
                try {
                    // const response = await axios.put(`${process.env.VUE_APP_API_URL}/api/[endpoint]/${id}`);
                    // updateSuccess.value = true;
                } catch (error) {
                    console.log(error);
                    Swal.showValidationMessage(
                        `Request failed: ${error}`
                    )
                }
            }
        }).then((result) => {
            console.log(result);
            if (result.isConfirmed){
                console.log("running something behind!")
                /* Swal.fire({
                    html: `
                        <p class="text-muted fw-bold mt-3 mb-2">success</p>`,
                    confirmButtonText: 'Exit',
                    showCloseButton: true,
                    customClass: {
                        confirmButton: 'btn btn-secondary fw-bold px-5 mx-3',
                        actions: 'd-flex justify-content-end me-5 ms-0',
                    },
                    buttonsStyling: false
                }) */
            }else{
                console.log(result.isConfirmed, result.dismiss)
                isVerifiedNumberError.value = true;
            }
        })

    };

    const submitVerificationCode = async() => {
        try {
            errors.value = {};
            isSubmitLoading.value = true;
            const savedNumbers = ["2291387761","2291345567"];
            await verifySchema.validate( verifyModel.value, { abortEarly: false });
            await verifiedNumbers(savedNumbers).validate({'phone_number': verifyModel.value.phone_number}, { abortEarly: false});
            //send initial code
            testCodeSent(true)
        } catch (error) {
            isSubmitLoading.value = false;
            if(error?.name == 'ValidationError'){
                error.inner.forEach((err) => {
                    errors.value = { ...errors.value, [err.path]: i18n.global.t(err.message) };
                });
            }else{
                const errorMsg = throwErrorMessage(error);
                errorResponse.value = true;
                responseMsg.value = errorMsg;
            }
        }
    }

    const testCodeSent = (val) => {
        isSubmitLoading.value = true;
        setTimeout(() =>{
            isSubmitLoading.value = false;
            showCVComponent.value = true;
        },1600);

        setTimeout(() => {
            verifiedResponse.phoneNumber = verifyModel.value.phone_number;
            if(val){
                verifiedResponse.status = true;
                verifiedResponse.statusName = 'sent';
            }else{
                verifiedResponse.status = false;
                verifiedResponse.statusName = 'notSent';
            }
        }, 15000);
    }

    const verifyCode = () => {
        const code = 3316;
        let count = 0;
        // compare the verification code, count the failed captured attempts
        console.log(`captured code: ${verificationCode.value}, attempts ${attempts.value}`);
        if(verificationCode.value != code && attempts.value > 0){
            attempts.value = attempts.value - 1;
            verifiedNumberLabels.attemptsLabel = i18n.global.t('verifiedNumber.component.attemptsLabel', { attempts: attempts.value});
            verifiedResponse.status = true;
            verifiedResponse.statusName = 'failed_attempts';
            if(attempts.value == 0) {
                attempts.value = 3;
                isVerifiedNumberError.value = true;

            }
        }else{
            isVerifiedNumberSuccess.value = true;
            attempts.value = 3;
            verifyModel.value.phoneNumber = "";
        }
    }

    const sendNewCode = () => {
        console.log("reset status")
        verificationCode.value = "";
        verifiedResponse.status = true;
        verifiedResponse.statusName = 'sending';
        verifiedResponse.phoneNumber = verifyModel.value.phone_number;
        setTimeout(() => {
            verifiedResponse.statusName = 'sent';
        }, 14000);
    }

    const initCFComponent = () => {
        attempts.value = 3;
        showCVComponent.value = false;
        isVerifiedNumberSuccess.value = false;
        isVerifiedNumberError.value = false;
        verificationCode.value = "";
        verifyModel.value = {};
        togglePhoneType.value = false;
    }
    //const loading = ref(true);
    const initGetCountryCodes = async() => {
        if(countryCodes.value.length > 0) return;
        const { data : { data: {payload} } } = await getCountryCodes();
        countryCodes.value = payload;
        loading.value = false;
    }

    getStatus();

    /* getCountryCodes()
    .then(e => {
        countryCodes.value = e.data.data.payload;
    }).catch(error => {
        console.warn(error)
    }); */

</script>

<style src="@vueform/multiselect/themes/default.css"></style>
<style>
    .w-150px {
        width: 150px!important;
    }
</style>
<style scoped>
    .multiselect-custom {
        --ms-tag-bg: #2A7DDC;
        --ms-option-bg-selected-pointed: #2A7DDC;
    }
    .custom-input-group.with-icon>i {
        -webkit-transform: translateY(-50%);
        -ms-transform: translateY(-50%);
        transform: translateY(-50%);
        pointer-events: none;
        position: absolute;
        z-index: 3;
        top: 50%;
    }

    .custom-input-group.with-icon>i,
    .custom-input-group.with-icon.icon-right>i{
        right: .7rem;
    }

    .custom-input-group.with-icon>input,
    .custom-input-group.with-icon.icon-right>input {
        padding-right: 1.7rem;
    }

    /* .swal2-actions{
        justify-content: end !important;
        margin: 1.25em 2rem 0px;
    } */
    
    .swal2-html-container{
        padding-right: 3rem !important;
        padding-left: 3rem !important;
    }
</style>