File: //home/arjun/projects/buyercall/buyercall/assets/vue/widgets/PartnershipTable/PartnershipTable.vue
<template>
<div class="height-set" id="partnership-table">
<div class="spinner-main">
<Loader :loading="widgetLoading"> </Loader>
</div>
<template v-if="!widgetLoading && tableData.length">
<div class="card height-set">
<div class="card-body">
<h4 class="card-title">Partnership Table</h4>
<div class="row mt-4">
<!-- Search Bar Widget-->
<div class="col-sm-12 col-md-2">
<div id="tickets-table_filter" class="dataTables_filter">
<label class="d-inline-flex align-items-center">
Search:
<b-form-input
v-model="filter"
type="search"
placeholder="Search..."
class="form-control form-control-sm ms-2"
></b-form-input>
</label>
</div>
</div>
<!-- Page Limit Widget-->
<div class="col-sm-12 col-md-2">
<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="perPage"
size="sm"
:options="pageOptions"
></b-form-select
> entries
</label>
</div>
</div>
<!-- Add New Partnership Button-->
<div class="col-sm-12 col-md-8 text-md-end text-sm-start">
<button
type="button"
class="btn btn-primary waves-effect waves-light btn-addNewPartnerShip"
@click="addPartnershipModalShow = true"
>
Add New Partnership
</button>
</div>
</div>
<!-- Partnership List -->
<div class="table-responsive mb-0">
<b-table
class="datatables"
:items="tableData"
:fields="fields"
responsive="sm"
:per-page="perPage"
:current-page="currentPage"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:filter="filter"
:filter-included-fields="filterOn"
@filtered="onFiltered"
:bordered="true"
thead-class="table-light"
>
<template #cell(action)="data">
<button
type="button"
class="btn btn-light waves-effect"
@click="selectPartner(data.item)"
>
View
</button>
</template>
</b-table>
</div>
<div class="row">
<div class="col">
<div class="dataTables_paginate paging_simple_numbers float-end">
<ul class="pagination pagination-rounded mb-0">
<!-- pagination -->
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
></b-pagination>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- View Partnership Details Modalss -->
<b-modal
v-model="modalShow"
id="workflow-modal"
dialog-class="modal-dialog-slideout"
:hide-footer="true"
content-class="rounded-0"
>
<template #modal-header="{ close }">
<button type="button" class="btn btn-primary" @click="close()">
<i class="bx bx-left-arrow-alt font-size-16 align-middle me-2"></i>
Back
</button>
</template>
<partnership-details
v-if="selectedPartner"
:selectedPartner="selectedPartner"
:billingTypes="billingTypes"
:businessTypes="businessTypes"
:partnerTypes="partnerTypes"
:roles="roles"
@accountClosed="unselectPartner"
></partnership-details
></b-modal>
<!-- Add Partnership Modal -->
<b-modal
v-model="addPartnershipModalShow"
dialog-class="modal-dialog-slideout"
title-class="font-18"
size="xl"
content-class="rounded-0"
footer-class="text-end"
:hide-footer="true"
id="workflow-modal"
>
<template #modal-header="{ close }">
<button type="button" class="btn btn-primary" @click="close()">
<i class="bx bx-left-arrow-alt font-size-16 align-middle me-2"></i>
Close
</button>
</template>
<div class="row justify-content-center">
<div class="col-xl-10">
<div class="card">
<div class="card-body">
<h4 class="card-title">Add New Partnership</h4>
<b-form @submit.prevent="modalformSubmit">
<div class="row">
<div class="col-md-6 text-center">
<div class="mt-4 mt-md-0 mb-1">
<div
class="profile-avatar border-radius-0 avatar-lg"
v-if="!avatar"
>
{{ avatarName }}
</div>
<template v-else>
<p class="text-muted">Partnership Large Logo</p>
<img
class="avatar-lg w-auto"
alt="200x200"
:src="renderImageUrl"
data-holder-rendered="true"
/>
</template>
</div>
<b-button variant="link" class="image-change-button pt-0"
><input
class="form-control"
type="file"
@change="onChangeAvatar"
/><span
>{{ !avatar ? "Upload Large Logo" : "Change" }}
</span></b-button
>
<span v-if="avatar"> | </span>
<b-button
variant="link"
class="image-change-button pt-0"
v-if="avatar"
@click="avatar = null"
>
<span>Remove</span>
</b-button>
<p>
<em class="image-size-specify-tag">Optimal size: Height >70px</em>
</p>
</div>
<div class="col-md-6 text-center">
<div class="mt-4 mt-md-0 mb-1">
<div
class="profile-avatar avatar-lg border-radius-0"
v-if="!avatarSmall"
>
{{ avatarName }}
</div>
<template v-else>
<p class="text-muted">Partnership Small Logo</p>
<img
class="avatar-lg"
alt="200x200"
:src="renderImageUrlSmall"
data-holder-rendered="true"
/>
</template>
</div>
<b-button variant="link" class="image-change-button pt-0"
><input
class="form-control"
type="file"
@change="onChangeAvatarSmall"
/><span
>{{ !avatarSmall ? "Upload Small Logo" : "Change" }}
</span></b-button
>
<span v-if="avatarSmall"> | </span>
<b-button
variant="link"
class="image-change-button pt-0"
v-if="avatarSmall"
@click="avatarSmall = null"
>
<span>Remove</span>
</b-button>
<p>
<em class="image-size-specify-tag"
>Optimal size: >70px X >70px</em
>
</p>
</div>
<div class="col-md-12">
<b-form-group
class="mb-3"
label="Partnership name"
label-for="formrow-partnershipname-input"
>
<b-form-input
id="formrow-partnershipname-input"
type="text"
placeholder="Partnership name"
v-model="form.partnershipName"
name="partnershipName"
:class="{
'is-invalid': submitted && $v.form.partnershipName.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.form.partnershipName.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.partnershipName.required"
>This value is required.</span
>
</div>
</b-form-group>
</div>
</div>
<div class="row">
<div class="col-md-4 mb-3">
<label>Current Default Billing</label>
<multiselect
v-model="form.defaultBilling"
:options="billingTypes"
:class="{
'is-invalid': submitted && $v.form.defaultBilling.$error,
}"
placeholder="Select billing type"
label="label"
></multiselect>
<div
v-if="submitted && $v.form.defaultBilling.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.defaultBilling.required"
>This value is required.</span
>
</div>
</div>
<div class="col-md-4 mb-3">
<label>Business Type</label>
<multiselect
v-model="form.businessType"
:options="businessTypes"
:class="{
'is-invalid': submitted && $v.form.businessType.$error,
}"
placeholder="Business Type"
label="label"
></multiselect>
<div
v-if="submitted && $v.form.businessType.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.businessType.required"
>This value is required.</span
>
</div>
</div>
<div class="col-md-4 mb-3">
<label>Partner Type</label>
<multiselect
v-model="form.partnerType"
:options="partnerTypes"
:class="{
'is-invalid': submitted && $v.form.partnerType.$error,
}"
placeholder="Partner Type"
label="label"
></multiselect>
<div
v-if="submitted && $v.form.partnerType.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.partnerType.required"
>This value is required.</span
>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<b-form-group
class="mb-3"
label="Partner Domain"
label-for="formrow-partnerurl-input"
>
<b-form-input
id="formrow-partnerurl-input"
type="text"
placeholder="Partner Url"
v-model="form.partnerUrl"
name="partnerUrl"
:class="{
'is-invalid': submitted && $v.form.partnerUrl.$error,
}"
>
</b-form-input>
<div
v-if="submitted && $v.form.partnerUrl.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.partnerUrl.required"
>This value is required.</span
>
<span v-else-if="!$v.form.partnerUrl.domainValidator">{{
formvalidationMessages.domainvalidatorMessage
}}</span>
</div>
</b-form-group>
</div>
<div class="col-md-6">
<!-- <photoshop-picker v-model="sidebarColor" /> -->
<b-form-group class="mb-3" label="Select Primary Color">
<b-input-group>
<template #prepend>
<!-- <v-input-colorpicker
v-model="form.sidebarColor"
:style="{ backgroundColor: form.sidebarColor }"
/> -->
</template>
<b-form-input
id="formrow-colorpicker-input"
type="text"
placeholder="Select Primary Color"
v-model="form.sidebarColor"
name="colorpicker"
></b-form-input>
</b-input-group>
</b-form-group>
</div>
<div class="col-md-6">
<b-form-group
class="mb-3"
label="Default System Email"
label-for="formrow-systememail-input"
>
<b-form-input
id="formrow-systememail-input"
type="text"
placeholder="Default system email"
v-model="form.systemEmail"
name="systemEmail"
:class="{
'is-invalid': submitted && $v.form.systemEmail.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.form.systemEmail.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.systemEmail.required"
>This value is required.</span
>
<span v-else-if="!$v.form.partnerUrl.email"
>Please provide a valid email.</span
>
</div>
</b-form-group>
</div>
<div class="col-md-6">
<b-form-group
class="mb-3"
label="Invite Partner User Email"
label-for="formrow-systememail-input"
>
<b-form-input
id="formrow-partneruseremail-input"
type="text"
placeholder="Invite partner user email"
v-model="form.partneruseremail"
name="partneruseremail"
:class="{
'is-invalid': submitted && $v.form.partneruseremail.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.form.partneruseremail.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.partneruseremail.required"
>This value is required.</span
>
<span v-else-if="!$v.form.partneruseremail.email"
>Please provide a valid email.</span
>
</div>
</b-form-group>
</div>
<div class="col-md-6">
<div class="form-check form-switch mb-3 form-switch-lg">
<input
class="form-check-input"
type="checkbox"
id="restrictLoginAccess"
v-model="form.expandedMenu"
/>
<label class="form-check-label" for="restrictLoginAccess"
>Display expanded menu as default</label
>
</div>
</div>
</div>
<div>
<b-button variant="light" @click="closeModalAddPartnership">
Cancel</b-button
>
<b-button variant="primary" type="submit" @click="modalSubmitClicked">
<i
class="bx bx-loader bx-spin font-size-16 align-middle me-2"
v-if="addPartnershipLoading"
></i>
Confirm
</b-button>
</div>
</b-form>
</div>
</div>
</div>
</div>
</b-modal>
</template>
</div>
</template>
<script>
import PartnershipService from "../../service/partnershipService";
import MainService from "../../service/mainService";
import Loader from "../../components/Loader/loader.vue";
import PartnershipDetails from "./PartnershipDetails.vue";
import { toastConfig } from "../../utils/util";
import { required, email, url } from "vuelidate/lib/validators";
import Multiselect from "vue-multiselect";
import * as _ from "lodash";
import InputColorPicker from "vue-native-color-picker";
import {
BFormInput,
BFormSelect,
BTable,
BPagination,
BModal,
BButton,
BFormGroup,
BInputGroup,
BForm,
} from "bootstrap-vue-next";
import {
formvalidation,
formvalidationMessages,
isFileWithinLimit,
} from "../../utils/util";
const { domainValidator } = formvalidation;
export default {
components: {
Loader,
PartnershipDetails,
Multiselect,
InputColorPicker,
BFormInput,
BFormSelect,
BTable,
BPagination,
BModal,
BButton,
BFormGroup,
// VInputColorpicker,
BInputGroup,
BForm,
},
data() {
return {
formvalidationMessages,
partnershipListLoading: false,
addPartnershipModalShow: false,
billingTypesLoading: false,
businessTypesLoading: false,
partnerTypesLoading: false,
addPartnershipLoading: false,
roleLoading: false,
billingTypes: [],
businessTypes: [],
partnerTypes: [],
roles: [],
selectedPartner: null,
modalShow: false,
headVariant: "light",
tableData: [],
totalRows: 1,
currentPage: 1,
perPage: 5,
pageOptions: [5, 10, 25, 50, 100],
filter: null,
filterOn: [],
sortBy: "partnershipName",
sortDesc: false,
fields: [
{
key: "partnershipName",
sortable: true,
},
{
key: "created_on",
sortable: true,
},
{
key: "updated_on",
sortable: true,
},
"action",
],
avatar: null,
avatarSmall: null,
form: {
partnershipName: "",
defaultBilling: null,
businessType: null,
partnerType: null,
partnerUrl: "",
systemEmail: "",
partneruseremail: "",
sidebarColor: "#2a3042",
expandedMenu: false,
},
submitted: false,
};
},
validations: {
form: {
partnershipName: { required },
defaultBilling: { required },
businessType: { required },
partnerType: { required },
partnerUrl: { required, domainValidator },
systemEmail: { required, email },
partneruseremail: { required, email },
},
},
mounted() {
this.getPartnerships();
this.getBillingTypes();
this.getBusinessTypes();
this.getRoles();
this.getPartnerTypes();
},
computed: {
/**
* Total no. of records
*/
rows() {
return this.tableData.length;
},
/**
* Total no. of records
*/
widgetLoading() {
return (
this.partnershipListLoading ||
this.billingTypesLoading ||
this.roleLoading ||
this.partnerTypesLoading ||
this.businessTypesLoading
);
},
avatarName() {
if (!this.form.partnershipName) {
return "";
}
return this.form.partnershipName.charAt(0).toUpperCase();
},
renderImageUrl() {
if (this.avatar == null) {
return null;
}
const image =
typeof this.avatar === "object" ? URL.createObjectURL(this.avatar) : this.avatar;
return image;
},
renderImageUrlSmall() {
if (this.avatarSmall == null) {
return null;
}
const image =
typeof this.avatarSmall === "object"
? URL.createObjectURL(this.avatarSmall)
: this.avatarSmall;
return image;
},
},
methods: {
modalSubmitClicked(e) {
e.preventDefault();
this.modalformSubmit();
},
closeModalAddPartnership() {
this.addPartnershipModalShow = false;
this.v$.form.$reset();
},
/**
* Search the table data with search input
*/
onFiltered(filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.totalRows = filteredItems.length;
this.currentPage = 1;
},
modalformSubmit() {
this.submitted = true;
this.v$?.$touch();
if (this.v$?.$invalid) {
return;
}
const formData = new FormData();
formData.append("data", JSON.stringify(this.form));
if (this.avatar !== null && typeof this.avatar === "object") {
formData.append("file", this.avatar);
}
if (this.avatarSmall !== null && typeof this.avatarSmall === "object") {
formData.append("filesmall", this.avatarSmall);
}
this.addPartnership(formData);
},
onChangeAvatar(e) {
const { files } = e.target;
if (files && files[0]) {
const tempFiles = [...files];
if (
tempFiles[0].type.includes("image") &&
isFileWithinLimit(files[0].size / 1024 / 1024, 5)
) {
let reader = new FileReader();
reader.readAsDataURL(tempFiles[0]);
reader.onload = (evt) => {
let img = new Image();
img.onload = () => {
if (img.height < 70) {
this.$toast.open(
toastConfig.toastError("The image should have a minmum height of 70px.")
);
} else {
this.avatar = tempFiles[0];
}
};
img.src = evt.target.result;
};
} else {
this.$toast.open(
toastConfig.toastError(
"The file should be an image and should be less than 5MB"
)
);
}
}
e.target.value = "";
},
onChangeAvatarSmall(e) {
const { files } = e.target;
if (files && files[0]) {
const tempFiles = [...files];
if (
tempFiles[0].type.includes("image") &&
isFileWithinLimit(tempFiles[0].size / 1024 / 1024, 5)
) {
let reader = new FileReader();
reader.readAsDataURL(tempFiles[0]);
reader.onload = (evt) => {
let img = new Image();
img.onload = () => {
if (img.height < 70 || img.width < 70) {
this.$toast.open(
toastConfig.toastError(
"The image should have a minmum height and width of 70px."
)
);
} else if (img.height !== img.width) {
this.$toast.open(
toastConfig.toastError("The height and width of image should be same.")
);
} else {
this.avatarSmall = tempFiles[0];
}
};
img.src = evt.target.result;
};
} else {
this.$emit(
"toast",
toastConfig.toastError(
"The file should be an image and should be less than 5MB"
)
);
}
}
e.target.value = "";
},
resetForm() {
this.form = {
partnershipName: "",
defaultBilling: null,
businessType: null,
partnerType: null,
partnerUrl: "",
systemEmail: "",
partneruseremail: "",
sidebarColor: "#2a3042",
};
this.avatar = null;
this.avatarSmall = null;
},
/**
* Get all partnerships
*/
getPartnerships() {
this.partnershipListLoading = true;
PartnershipService.getPartnerships()
.then(({ data: { success, message, data } }) => {
if (success) {
// console.log(success, message, data);
// this.$toast.open(toastConfig.toastSuccess(message));
this.partnershipListLoading = false;
this.tableData = data;
} else {
this.$toast.open(toastConfig.toastError(message));
this.partnershipListLoading = false;
}
})
.catch((e) => {
this.partnershipListLoading = false;
this.$toast.open(
toastConfig.toastError(
"Something went wrong while fetching partnership list!"
)
);
console.log("error", e);
});
},
getBillingTypes() {
this.billingTypesLoading = true;
PartnershipService.getPartnershipBillingTypes()
.then(({ data: { success, message, data } }) => {
if (success) {
// console.log(success, message, data);
// this.$toast.open(toastConfig.toastSuccess(message));
this.billingTypesLoading = false;
this.billingTypes = data;
} else {
this.$toast.open(toastConfig.toastError(message));
this.billingTypesLoading = false;
}
})
.catch((e) => {
this.billingTypesLoading = false;
this.$toast.open(
toastConfig.toastError("Something went wrong while fetching billing types!")
);
console.log("error", e);
});
},
getBusinessTypes() {
this.businessTypesLoading = true;
PartnershipService.getPartnershipBusinessTypes()
.then(({ data: { success, message, data } }) => {
if (success) {
// console.log(success, message, data);
// this.$toast.open(toastConfig.toastSuccess(message));
this.businessTypesLoading = false;
this.businessTypes = data;
} else {
this.$toast.open(toastConfig.toastError(message));
this.businessTypesLoading = false;
}
})
.catch((e) => {
this.businessTypesLoading = false;
this.$toast.open(
toastConfig.toastError("Something went wrong while fetching business types!")
);
console.log("error", e);
});
},
getRoles() {
this.roleLoading = true;
MainService.getAppRoles()
.then(({ data: { success, message, data } }) => {
if (success) {
this.roleLoading = false;
this.roles = data;
} else {
this.$toast.open(toastConfig.toastError(message));
this.roleLoading = false;
}
})
.catch((e) => {
this.roleLoading = false;
console.log("error", e);
this.$toast.open(
toastConfig.toastError("Something went wrong while fetching app roles!")
);
});
},
getPartnerTypes() {
this.partnerTypesLoading = true;
PartnershipService.getPartnershipTypes()
.then(({ data: { success, message, data } }) => {
if (success) {
this.partnerTypesLoading = false;
this.partnerTypes = data;
} else {
this.$toast.open(toastConfig.toastError(message));
this.partnerTypesLoading = false;
}
})
.catch((e) => {
this.partnerTypesLoading = false;
console.log("error", e);
this.$toast.open(
toastConfig.toastError("Something went wrong while fetching partner types!")
);
});
},
addPartnership(postData) {
this.addPartnershipLoading = true;
PartnershipService.addPartnership(postData)
.then(({ data: { success, message } }) => {
if (success) {
this.$toast.open(toastConfig.toastSuccess(message));
this.addPartnershipLoading = false;
this.closeModalAddPartnership();
this.resetForm();
this.getPartnerships();
} else {
this.$toast.open(toastConfig.toastError(message));
this.addPartnershipLoading = false;
}
})
.catch((e) => {
this.addPartnershipLoading = false;
console.log("error", e);
this.$toast.open(
toastConfig.toastError("Something went wrong while trying to add partnership")
);
});
},
/**
* Select a partner when clicking view button
*/
selectPartner(partnerData) {
this.selectedPartner = partnerData.sid;
this.modalShow = true;
},
unselectPartner() {
this.selectedPartner = null;
this.modalShow = false;
this.getPartnerships();
},
},
//directives: { "v-input-colorpicker": InputColorPicker },
watch: {
/**
* Watch modal triggering variable
*/
modalShow(flag) {
if (!flag) {
this.selectedPartner = null;
}
},
},
};
</script>