Changeset View
Changeset View
Standalone View
Standalone View
src/resources/vue/Admin/User.vue
<template> | <template> | ||||
<div class="container"> | <div class="container"> | ||||
<div class="card" id="user-info"> | <div class="card" id="user-info"> | ||||
<div class="card-body"> | <div class="card-body"> | ||||
<div class="card-title">{{ user.email }}</div> | <div class="card-title">{{ user.email }}</div> | ||||
<div class="card-text"> | <div class="card-text"> | ||||
<form> | <form class="read-only"> | ||||
<div v-if="user.wallet.user_id != user.id" class="form-group row mb-0"> | <div v-if="user.wallet.user_id != user.id" class="form-group row"> | ||||
<label for="manager" class="col-sm-4 col-form-label">Managed by</label> | <label for="manager" class="col-sm-4 col-form-label">Managed by</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="manager"> | <span class="form-control-plaintext" id="manager"> | ||||
<router-link :to="{ path: '/user/' + user.wallet.user_id }">{{ user.wallet.user_email }}</router-link> | <router-link :to="{ path: '/user/' + user.wallet.user_id }">{{ user.wallet.user_email }}</router-link> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0"> | <div class="form-group row"> | ||||
<label for="userid" class="col-sm-4 col-form-label">ID <span class="text-muted">(Created at)</span></label> | <label for="userid" class="col-sm-4 col-form-label">ID <span class="text-muted">(Created at)</span></label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="userid"> | <span class="form-control-plaintext" id="userid"> | ||||
{{ user.id }} <span class="text-muted">({{ user.created_at }})</span> | {{ user.id }} <span class="text-muted">({{ user.created_at }})</span> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0"> | <div class="form-group row"> | ||||
<label for="status" class="col-sm-4 col-form-label">Status</label> | <label for="status" class="col-sm-4 col-form-label">Status</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="status"> | <span class="form-control-plaintext" id="status"> | ||||
<span :class="$root.userStatusClass(user)">{{ $root.userStatusText(user) }}</span> | <span :class="$root.userStatusClass(user)">{{ $root.userStatusText(user) }}</span> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0" v-if="user.first_name"> | <div class="form-group row" v-if="user.first_name"> | ||||
<label for="first_name" class="col-sm-4 col-form-label">First name</label> | <label for="first_name" class="col-sm-4 col-form-label">First name</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="first_name">{{ user.first_name }}</span> | <span class="form-control-plaintext" id="first_name">{{ user.first_name }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0" v-if="user.last_name"> | <div class="form-group row" v-if="user.last_name"> | ||||
<label for="last_name" class="col-sm-4 col-form-label">Last name</label> | <label for="last_name" class="col-sm-4 col-form-label">Last name</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="last_name">{{ user.last_name }}</span> | <span class="form-control-plaintext" id="last_name">{{ user.last_name }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0" v-if="user.organization"> | <div class="form-group row" v-if="user.organization"> | ||||
<label for="organization" class="col-sm-4 col-form-label">Organization</label> | <label for="organization" class="col-sm-4 col-form-label">Organization</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="organization">{{ user.organization }}</span> | <span class="form-control-plaintext" id="organization">{{ user.organization }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0" v-if="user.phone"> | <div class="form-group row" v-if="user.phone"> | ||||
<label for="phone" class="col-sm-4 col-form-label">Phone</label> | <label for="phone" class="col-sm-4 col-form-label">Phone</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="phone">{{ user.phone }}</span> | <span class="form-control-plaintext" id="phone">{{ user.phone }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0"> | <div class="form-group row"> | ||||
<label for="external_email" class="col-sm-4 col-form-label">External email</label> | <label for="external_email" class="col-sm-4 col-form-label">External email</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="external_email"> | <span class="form-control-plaintext" id="external_email"> | ||||
<a v-if="user.external_email" :href="'mailto:' + user.external_email">{{ user.external_email }}</a> | <a v-if="user.external_email" :href="'mailto:' + user.external_email">{{ user.external_email }}</a> | ||||
<button type="button" class="btn btn-secondary btn-sm" @click="emailEdit">Edit</button> | <button type="button" class="btn btn-secondary btn-sm" @click="emailEdit">Edit</button> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0" v-if="user.billing_address"> | <div class="form-group row" v-if="user.billing_address"> | ||||
<label for="billing_address" class="col-sm-4 col-form-label">Address</label> | <label for="billing_address" class="col-sm-4 col-form-label">Address</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" style="white-space:pre" id="billing_address">{{ user.billing_address }}</span> | <span class="form-control-plaintext" style="white-space:pre" id="billing_address">{{ user.billing_address }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row mb-0"> | <div class="form-group row"> | ||||
<label for="country" class="col-sm-4 col-form-label">Country</label> | <label for="country" class="col-sm-4 col-form-label">Country</label> | ||||
<div class="col-sm-8"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="country">{{ user.country }}</span> | <span class="form-control-plaintext" id="country">{{ user.country }}</span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</form> | </form> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
Show All 23 Lines | <div class="container"> | ||||
<a class="nav-link" id="tab-users" href="#user-users" role="tab" aria-controls="user-users" aria-selected="false"> | <a class="nav-link" id="tab-users" href="#user-users" role="tab" aria-controls="user-users" aria-selected="false"> | ||||
Users ({{ users.length }}) | Users ({{ users.length }}) | ||||
</a> | </a> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
<div class="tab-content"> | <div class="tab-content"> | ||||
<div class="tab-pane show active" id="user-finances" role="tabpanel" aria-labelledby="tab-finances"> | <div class="tab-pane show active" id="user-finances" role="tabpanel" aria-labelledby="tab-finances"> | ||||
<div class="card-body"> | <div class="card-body"> | ||||
<div class="card-title">Account balance <span :class="balance < 0 ? 'text-danger' : 'text-success'"><strong>{{ $root.price(balance) }}</strong></span></div> | <div class="card-title">Account balance <span :class="wallet.balance < 0 ? 'text-danger' : 'text-success'"><strong>{{ $root.price(wallet.balance) }}</strong></span></div> | ||||
<div class="card-text"> | <div class="card-text"> | ||||
<form> | <form class="read-only"> | ||||
<div class="form-group row mb-0"> | <div class="form-group row"> | ||||
<label class="col-sm-2 col-form-label">Discount:</label> | <label class="col-sm-4 col-form-label">Discount</label> | ||||
<div class="col-sm-10"> | <div class="col-sm-8"> | ||||
<span class="form-control-plaintext" id="discount"> | <span class="form-control-plaintext" id="discount"> | ||||
<span>{{ wallet_discount ? (wallet_discount + '% - ' + wallet_discount_description) : 'none' }}</span> | <span>{{ wallet.discount ? (wallet.discount + '% - ' + wallet.discount_description) : 'none' }}</span> | ||||
<button type="button" class="btn btn-secondary btn-sm" @click="discountEdit">Edit</button> | <button type="button" class="btn btn-secondary btn-sm" @click="discountEdit">Edit</button> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row" v-if="wallet.mandate && wallet.mandate.id"> | |||||
<label class="col-sm-4 col-form-label">Auto-payment</label> | |||||
<div class="col-sm-8"> | |||||
<span class="form-control-plaintext" id="autopayment"> | |||||
Fill up by <b>{{ wallet.mandate.amount }} CHF</b> | |||||
when under <b>{{ wallet.mandate.balance }} CHF</b> | |||||
using {{ wallet.mandate.method }}.</span> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
<div class="form-group row" v-if="wallet.providerLink"> | |||||
<label class="col-sm-4 col-form-label">{{ capitalize(wallet.provider) }} ID</label> | |||||
<div class="col-sm-8"> | |||||
<span class="form-control-plaintext" v-html="wallet.providerLink"></span> | |||||
</div> | |||||
</div> | |||||
</form> | </form> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="tab-pane" id="user-aliases" role="tabpanel" aria-labelledby="tab-aliases"> | <div class="tab-pane" id="user-aliases" role="tabpanel" aria-labelledby="tab-aliases"> | ||||
<div class="card-body"> | <div class="card-body"> | ||||
<div class="card-text"> | <div class="card-text"> | ||||
<table class="table table-sm table-hover"> | <table class="table table-sm table-hover"> | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | <div class="container"> | ||||
<div class="modal-header"> | <div class="modal-header"> | ||||
<h5 class="modal-title">Account discount</h5> | <h5 class="modal-title">Account discount</h5> | ||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
<span aria-hidden="true">×</span> | <span aria-hidden="true">×</span> | ||||
</button> | </button> | ||||
</div> | </div> | ||||
<div class="modal-body"> | <div class="modal-body"> | ||||
<p class="form-group"> | <p class="form-group"> | ||||
<select v-model="wallet_discount_id" class="custom-select"> | <select v-model="wallet.discount_id" class="custom-select"> | ||||
<option value="">- none -</option> | <option value="">- none -</option> | ||||
<option v-for="item in discounts" :value="item.id" :key="item.id">{{ item.label }}</option> | <option v-for="item in discounts" :value="item.id" :key="item.id">{{ item.label }}</option> | ||||
</select> | </select> | ||||
</p> | </p> | ||||
</div> | </div> | ||||
<div class="modal-footer"> | <div class="modal-footer"> | ||||
<button type="button" class="btn btn-secondary modal-cancel" data-dismiss="modal">Cancel</button> | <button type="button" class="btn btn-secondary modal-cancel" data-dismiss="modal">Cancel</button> | ||||
<button type="button" class="btn btn-primary modal-action" @click="submitDiscount()"> | <button type="button" class="btn btn-primary modal-action" @click="submitDiscount()"> | ||||
Show All 36 Lines | export default { | ||||
// An event called when the route that renders this component has changed, | // An event called when the route that renders this component has changed, | ||||
// but this component is reused in the new route. | // but this component is reused in the new route. | ||||
// Required to handle links from /user/XXX to /user/YYY | // Required to handle links from /user/XXX to /user/YYY | ||||
next() | next() | ||||
this.$parent.routerReload() | this.$parent.routerReload() | ||||
}, | }, | ||||
data() { | data() { | ||||
return { | return { | ||||
balance: 0, | |||||
discount: 0, | discount: 0, | ||||
discount_description: '', | discount_description: '', | ||||
discounts: [], | discounts: [], | ||||
external_email: '', | external_email: '', | ||||
wallet_discount: 0, | wallet: {}, | ||||
wallet_discount_description: '', | |||||
wallet_discount_id: '', | |||||
domains: [], | domains: [], | ||||
skus: [], | skus: [], | ||||
users: [], | users: [], | ||||
user: { | user: { | ||||
aliases: [], | aliases: [], | ||||
wallet: {}, | wallet: {}, | ||||
skus: {}, | skus: {}, | ||||
} | } | ||||
} | } | ||||
}, | }, | ||||
created() { | created() { | ||||
const user_id = this.$route.params.user | const user_id = this.$route.params.user | ||||
this.$root.startLoading() | this.$root.startLoading() | ||||
axios.get('/api/v4/users/' + user_id) | axios.get('/api/v4/users/' + user_id) | ||||
.then(response => { | .then(response => { | ||||
this.$root.stopLoading() | this.$root.stopLoading() | ||||
this.user = response.data | this.user = response.data | ||||
let keys = ['first_name', 'last_name', 'external_email', 'billing_address', 'phone', 'organization'] | const financesTab = '#user-finances' | ||||
let country = this.user.settings.country | const keys = ['first_name', 'last_name', 'external_email', 'billing_address', 'phone', 'organization'] | ||||
const country = this.user.settings.country | |||||
if (country) { | if (country) { | ||||
this.user.country = window.config.countries[country][1] | this.user.country = window.config.countries[country][1] | ||||
} | } | ||||
keys.forEach(key => { this.user[key] = this.user.settings[key] }) | keys.forEach(key => { this.user[key] = this.user.settings[key] }) | ||||
this.discount = this.user.wallet.discount | this.discount = this.user.wallet.discount | ||||
this.discount_description = this.user.wallet.discount_description | this.discount_description = this.user.wallet.discount_description | ||||
// TODO: currencies, multi-wallets, accounts | // TODO: currencies, multi-wallets, accounts | ||||
this.user.wallets.forEach(wallet => { | // Get more info about the wallet (e.g. payment provider related) | ||||
this.balance += wallet.balance | this.$root.addLoader(financesTab) | ||||
axios.get('/api/v4/wallets/' + this.user.wallets[0].id) | |||||
.then(response => { | |||||
this.$root.removeLoader(financesTab) | |||||
this.wallet = response.data | |||||
}) | |||||
.catch(error => { | |||||
this.$root.removeLoader(financesTab) | |||||
}) | }) | ||||
this.wallet_discount = this.user.wallets[0].discount | |||||
this.wallet_discount_id = this.user.wallets[0].discount_id || '' | |||||
this.wallet_discount_description = this.user.wallets[0].discount_description | |||||
// Create subscriptions list | // Create subscriptions list | ||||
axios.get('/api/v4/skus') | axios.get('/api/v4/skus') | ||||
.then(response => { | .then(response => { | ||||
// "merge" SKUs with user entitlement-SKUs | // "merge" SKUs with user entitlement-SKUs | ||||
response.data.forEach(sku => { | response.data.forEach(sku => { | ||||
if (sku.id in this.user.skus) { | if (sku.id in this.user.skus) { | ||||
let count = this.user.skus[sku.id].count | let count = this.user.skus[sku.id].count | ||||
Show All 33 Lines | export default { | ||||
}, | }, | ||||
mounted() { | mounted() { | ||||
$(this.$el).find('ul.nav-tabs a').on('click', e => { | $(this.$el).find('ul.nav-tabs a').on('click', e => { | ||||
e.preventDefault() | e.preventDefault() | ||||
$(e.target).tab('show') | $(e.target).tab('show') | ||||
}) | }) | ||||
}, | }, | ||||
methods: { | methods: { | ||||
capitalize(str) { | |||||
return str.charAt(0).toUpperCase() + str.slice(1) | |||||
}, | |||||
discountEdit() { | discountEdit() { | ||||
$('#discount-dialog') | $('#discount-dialog') | ||||
.on('shown.bs.modal', e => { | .on('shown.bs.modal', e => { | ||||
$(e.target).find('select').focus() | $(e.target).find('select').focus() | ||||
// Note: Vue v-model is strict, convert null to a string | |||||
this.wallet.discount_id = this.wallet_discount_id || '' | |||||
}) | }) | ||||
.modal() | .modal() | ||||
if (!this.discounts.length) { | if (!this.discounts.length) { | ||||
// Fetch discounts | // Fetch discounts | ||||
axios.get('/api/v4/discounts') | axios.get('/api/v4/discounts') | ||||
.then(response => { | .then(response => { | ||||
this.discounts = response.data.list | this.discounts = response.data.list | ||||
}) | }) | ||||
} | } | ||||
}, | }, | ||||
emailEdit() { | emailEdit() { | ||||
this.external_email = this.user.external_email | this.external_email = this.user.external_email | ||||
this.$root.clearFormValidation($('#email-dialog')) | this.$root.clearFormValidation($('#email-dialog')) | ||||
$('#email-dialog') | $('#email-dialog') | ||||
.on('shown.bs.modal', e => { | .on('shown.bs.modal', e => { | ||||
$(e.target).find('input').focus() | $(e.target).find('input').focus() | ||||
}) | }) | ||||
.modal() | .modal() | ||||
}, | }, | ||||
submitDiscount() { | submitDiscount() { | ||||
$('#discount-dialog').modal('hide') | $('#discount-dialog').modal('hide') | ||||
axios.put('/api/v4/wallets/' + this.user.wallets[0].id, { discount: this.wallet_discount_id }) | axios.put('/api/v4/wallets/' + this.user.wallets[0].id, { discount: this.wallet.discount_id }) | ||||
.then(response => { | .then(response => { | ||||
if (response.data.status == 'success') { | if (response.data.status == 'success') { | ||||
this.$toast.success(response.data.message) | this.$toast.success(response.data.message) | ||||
this.wallet_discount = response.data.discount | this.wallet = Object.assign({}, this.wallet, response.data) | ||||
this.wallet_discount_id = response.data.discount_id || '' | |||||
this.wallet_discount_description = response.data.discount_description | |||||
// Update prices in Subscriptions tab | // Update prices in Subscriptions tab | ||||
if (this.user.wallet.id == response.data.id) { | if (this.user.wallet.id == response.data.id) { | ||||
this.discount = this.wallet_discount | this.discount = this.wallet.discount | ||||
this.discount_description = this.wallet_discount_description | this.discount_description = this.wallet.discount_description | ||||
this.skus.forEach(sku => { | this.skus.forEach(sku => { | ||||
sku.price = this.$root.priceLabel(sku.cost, sku.units, this.discount) | sku.price = this.$root.priceLabel(sku.cost, sku.units, this.discount) | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
}) | }) | ||||
}, | }, | ||||
Show All 14 Lines |