File: //home/arjun/projects/buyercall/buyercall/assets/vue/widgets/contactManagement/components/List.vue
<template>
<div class="spinner-main">
<growing-loader :isMini="true" v-if="loading"></growing-loader>
</div>
<div class="card height-set">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<h4 class="card-title">Leads List</h4>
<button
type="button"
class="btn btn-primary waves-effect waves-light btn-addNewPartnerShip"
@click="addNewLeads()"
>
Add New Lead
</button>
</div>
<div class="row" style="margin-top: -1.5rem !important">
<div class="row mt-4">
<template v-if="tableData.length == 0 || tableData.length">
<div class="col-sm-12 col-md-2" style="width: 350px">
<div id="tickets-table_filter" class="dataTables_filter">
<label class="d-inline-flex align-items-center w-100">
<b-form-input
v-model="filter"
type="search"
placeholder="Search for..."
class="form-control form-control-sm ms-2"
style="height: 40px"
></b-form-input>
</label>
</div>
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<datepicker
v-model="pickedFrom"
class="form-control form-control-sm"
:format="DatePickerFormat"
style="height: 38px"
/>
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<datepicker
v-model="pickedTo"
class="form-control form-control-sm"
:format="DatePickerFormat"
style="height: 38px"
/>
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<button
type="button"
class="btn btn-light waves-effect waves-light btn-addNewPartnerShip btn-width text-muted"
@click="downloadCSVItem()"
>
Download CSV
</button>
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<input
ref="fileInput"
type="file"
@change="handleFileUpload"
class="btn btn-light waves-effect waves-light btn-addNewPartnerShip btn-width"
style="display: none"
/>
<button
@click="triggerFileInput"
class="btn btn-light waves-effect waves-light btn-addNewPartnerShip btn-width text-muted"
>
Import Leads
</button>
<!-- <ul>
<li v-for="(row, index) in csvData" :key="index">{{ row }}</li>
</ul> -->
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<button
type="button"
class="btn btn-light waves-effect waves-light btn-addNewPartnerShip btn-width text-muted"
v-bind:class="{ 'btn-soft-secondary': isFilterActive }"
v-bind:style="{
'background-color': isFilterActive ? '#74788d' : '',
}"
@click="additionalFilters()"
>
<Icon
:icon="isFilterActive ? 'mdi:filter-outline' : 'mdi:filter-outline'"
:color="isFilterActive ? '#ffffff' : ''"
style="margin-right: 5px"
/>
<span :style="{ color: isFilterActive ? '#ffffff' : '' }">Filters</span>
</button>
</div>
<div class="col-sm-12 col-md-2" style="width: fit-content">
<button
type="button"
class="btn btn-light waves-effect waves-light btn-addNewPartnerShip btn-width text-muted"
@click="resetFilters()"
>
Reset Filters
</button>
</div>
</template>
</div>
</div>
<div class="table-responsive mb-0">
<b-table
class="datatables"
:items="filteredItems"
:fields="fields"
responsive="sm"
:per-page="tablelength"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:bordered="true"
thead-class="table-white"
:hover="true"
:striped="false"
:busy="loading"
:show-empty="true"
sticky-header="false"
>
<template #table-busy>
<growing-loader></growing-loader>
</template>
<template #cell(0)="data">
<span style="font-weight: 600">
{{ (currentPage - 1) * perPage + data.index + 1 }}
</span>
</template>
<template #cell(1)="data">
<div style="display: flex; flex-direction: column">
<span>{{ data.item["1"] + " " + data.item["10"] }}</span>
</div>
</template>
<template #cell(2)="data">
<div style="display: flex; flex-direction: column">
<span>{{ data.item["2"] }}</span>
</div>
</template>
<template #cell(3)="data">
<div style="display: flex; flex-direction: column">
<span>{{ data.item["3"] }}</span>
</div>
</template>
<template #cell(4)="data">
<div>
<span class="sourcetype" v-if="data.item['4'] === 'import '">Import</span>
<span class="sourcetypecredit" v-if="data.item['4'] === ''">Credit</span>
</div>
</template>
<template #cell(is_active)="data">
<span class="badge bg-info" v-if="data.item.isActive">YES</span>
<span class="badge bg-danger" v-else>NO</span>
</template>
<template #cell(status)="data">
<span class="badge bg-success" v-if="data.item.status === 1">Ready</span>
<span class="badge bg-warning" v-if="data.item.status === 0">Warning</span>
</template>
<template #cell(action)="data">
<div class="btn-group">
<button
type="button"
class="btn btn-light waves-effect"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Action
</button>
<div class="dropdown-menu dropdown-menu-right">
<button class="dropdown-item" @click="quickEdit(data.item)">Edit</button>
</div>
</div>
</template>
</b-table>
</div>
<div class="row">
<div class="col d-flex justify-content-between align-items-center">
<div id="tickets-table_length" class="dataTables_length">
<label class="d-inline-flex align-items-center">
Show
<b-form-select
class="form-select form-select-sm"
v-model="tablelength"
size="sm"
:options="pageOptions"
style="height: 40px"
@change="handleAssignedAgentChange"
></b-form-select
>
</label>
</div>
<div class="dataTables_paginate paging_simple_numbers float-end">
<ul class="pagination pagination-rounded mb-0">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
@update:modelValue="fetchData"
></b-pagination>
</ul>
</div>
</div>
</div>
<leads-popup
v-if="showConfirmDelete"
@fileupload="showFileInput"
@downloadcsv="sampleTemplateDownload"
@cancel="cancel"
></leads-popup>
</div>
</div>
</template>
<script>
import { listTableConfig } from "../constants";
import GrowingLoader from "../../../components/GrowingLoader.vue";
import { BTable, BFormInput, BFormSelect, BPagination } from "bootstrap-vue-next";
import Datepicker from "vue3-datepicker";
import { Icon } from "@iconify/vue";
import LeadsPopup from "./LeadsPopup.vue";
import Papa from "papaparse";
import _ from "lodash";
export default {
emits: [
"onAddButtonClicked",
"onDelete",
"onAddFiltersClicked",
"onErrorMethod",
"reset",
"onEditContact",
"uploadcsv",
"datefilter",
"page-changed",
"page-show",
],
props: {
leadsData: {
type: Array,
required: true,
default: () => [],
},
leadInfo: {
type: Object,
required: true,
},
loading: {
type: Boolean,
required: true,
},
isFilterActive: {
type: Boolean,
required: true,
},
fromdate: {
type: Date,
required: true,
},
todate: {
type: Date,
required: true,
},
currentPages: {
type: Number,
required: true,
},
totalpage: {
type: Number,
required: true,
},
},
data() {
return {
tableData: [],
tablelength: 10,
currentPage: 1,
tablestart: 0,
dataSingObjectArray: [],
sampleTemplateData: listTableConfig.sampleTemplate,
sampleTemplaeHeading: listTableConfig.sampleTemplateHeading,
csvkeys: listTableConfig.CSV_KEYS,
csvHeading: listTableConfig.downloadAllCSV,
SEARCH_KEYS: listTableConfig.SEARCH_KEYS,
filter: null,
showConfirmDelete: false,
fromDate: "",
// pickedFrom: new Date("2010-01-01"),
// pickedTo: new Date(),
pickedFrom: null,
pickedTo: null,
DatePickerFormat: "dd/MM/yyyy",
disabledDates: {
to: new Date(Date.now() - 8640000),
},
csvData: [],
...listTableConfig,
};
},
computed: {
rows() {
// return this.leadInfo.recordsTotal;
return Math.ceil((this.leadInfo.recordsTotal / this.tablelength) * 10);
},
filteredItems() {
// Perform case-insensitive search based on the search query
const query = this.filter ? this.filter.toLowerCase() : "";
if (query) {
return this.tableData.filter((item) => {
return this.SEARCH_KEYS.some((key) =>
(item[key]?.toString()?.toLowerCase() || "").includes(query)
);
});
} else {
return this.tableData;
}
},
},
methods: {
handleAssignedAgentChange(e) {
this.tablelength = e;
this.tablestart = 0;
this.selectedDateFrom();
this.$emit("page-show", e);
},
fetchData(e) {
this.currentPage = e; // Update currentPage with the new page number
this.tablestart = (this.currentPage - 1) * this.tablelength; // Calculate tablestart based on currentPage
this.$emit("page-changed", e);
this.selectedDateFrom();
},
selectedDateFrom() {
let filters = {
df: this.formatDates(this.pickedFrom),
dt: this.formatDates(this.pickedTo),
stf: "0",
stp: "0",
sts: "0",
sis: "0",
sas: "0",
sais: "0",
length: this.tablelength,
start: this.tablestart,
aa: null,
ps: null,
ms: null,
mks: null,
fs: null,
cs: null,
cbs: null,
order: [
{
dir: "desc",
column: "5",
},
],
};
let selecteddate = {
from: this.pickedFrom,
to: this.pickedTo,
};
this.$emit("datefilter", filters, selecteddate);
},
formatDates(selecteddate) {
const dateObject = new Date(selecteddate);
const day = ("0" + dateObject.getDate()).slice(-2);
const month = ("0" + (dateObject.getMonth() + 1)).slice(-2);
const year = dateObject.getFullYear();
this.formattedDate = `${month}${day}${year}`;
return this.formattedDate;
},
resetFilters() {
this.currentPage = 1;
this.$emit("reset");
},
triggerFileInput(event) {
this.showConfirmDelete = true;
},
showFileInput() {
this.showConfirmDelete = false;
this.$refs.fileInput.click();
},
sampleTemplateDownload() {
this.showConfirmDelete = false;
const csvContent =
"data:text/csv;charset=utf-8," +
this.sampleTemplaeHeading.join(",") +
"\n" +
this.sampleTemplateData
.map((item) => this.sampleTemplaeHeading.map((key) => item[key]).join(","))
.join("\n");
// Create a data URI for the CSV content
const encodedUri = encodeURI(csvContent);
// Create a link element and trigger a download
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "SampleLeadsTemplate.csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
handleFileUpload(event) {
const file = event.target.files[0];
// Perform a simple validation based on the file extension
if (!file || !file.name.toLowerCase().endsWith(".csv")) {
this.error = "Please select a valid CSV file.";
this.$emit("onErrorMethod", "Please select a valid CSV file.");
return "";
}
// Clear any previous error messages
this.error = null;
// Parse the CSV file
Papa.parse(file, {
complete: (result) => {
// Apply transformations to the parsed data
this.csvData = result.data
.filter((item) => Object.keys(item).length > 1)
.map((item) => ({
...item,
zip: item.zip.toString(), // Convert zip to a string
}));
this.$emit("uploadcsv", this.csvData);
},
header: true, // set to true if your CSV file has a header row
dynamicTyping: true,
});
},
quickEdit(item) {
this.$emit("onEditContact", item["11"]);
},
downloadCSVItem(item) {
let csvContent = "";
const dataArray = item ? [item] : this.tableData;
if (dataArray.length > 0) {
csvContent =
"data:text/csv;charset=utf-8," +
this.csvHeading.join(",") +
"\n" +
dataArray
.map((item) =>
this.CSV_KEYS.map((key) => item[key] || "") // Handle undefined values
.join(",")
)
.join("\n");
// Create a data URI for the CSV content
const encodedUri = encodeURI(csvContent);
// Create a link element and trigger a download
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "leads.csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
},
addNewLeads() {
this.$emit("onAddButtonClicked");
},
additionalFilters() {
this.$emit("onAddFiltersClicked");
},
cancel() {
this.showConfirmDelete = false;
},
},
components: {
GrowingLoader,
BTable,
BFormInput,
BFormSelect,
BPagination,
Datepicker,
Icon,
LeadsPopup,
},
watch: {
leadsData: {
immediate: true,
handler(newVal) {
if (newVal) {
this.tableData = newVal;
}
},
},
isFilterActive: {
immediate: true,
handler(newVal) {},
},
pickedFrom(newValue, oldValue) {
if (newValue !== oldValue) {
if (oldValue) {
this.selectedDateFrom();
this.currentPage = 1;
}
}
},
pickedTo(newValue, oldValue) {
if (newValue !== oldValue) {
if (oldValue) {
this.selectedDateFrom();
this.currentPage = 1;
}
}
},
fromdate: {
immediate: true,
handler(newVal) {
this.pickedFrom = newVal;
},
},
todate: {
immediate: true,
handler(newVal) {
this.pickedTo = newVal;
},
},
currentPages: {
immediate: true,
handler(newVal) {
if (newVal !== this.currentPage) {
this.currentPage = newVal;
}
},
},
totalpage: {
immediate: true,
handler(newVal) {
if (newVal !== this.currentPage) {
this.tablelength = newVal;
}
},
},
},
};
</script>