Skip to content

Instantly share code, notes, and snippets.

@yoovanr
Created July 23, 2021 10:46
Show Gist options
  • Save yoovanr/a545b022b15a00aac4da665cd90e7584 to your computer and use it in GitHub Desktop.
Save yoovanr/a545b022b15a00aac4da665cd90e7584 to your computer and use it in GitHub Desktop.
[Vue] pages/settings/accounts/index.vue
<template>
<div class="accounts-staff">
<!-- top start -->
<div class="accounts-staff__top bottom-24">
<AppTitle
class="mb-0"
bold="Accounts & permissions"
/>
<AppButton
size="small"
@click.native="$router.push({ name: 'settings-accounts-add' })"
>
Add account
</AppButton>
</div>
<!-- top end -->
<!-- lower start -->
<div class="accounts-staff__lower">
<!-- table start -->
<div class="vtable-wrapper">
<v-card>
<v-card-title>
<v-text-field
@input="updateAccountUsersSearch"
append-icon="mdi-magnify"
label="Search by name, e-mail, staff-id…"
single-line
hide-details
v-model="searchManagerValue"
></v-text-field>
</v-card-title>
<client-only>
<v-data-table
v-if="accountUsersData && accountUsersData.headers"
:headers="accountUsersData.headers"
:items="accountUsersData.content"
:search="search"
hide-default-footer
disable-pagination
>
<template v-slot:item="row">
<tr>
<td>
<input
type="text"
:class="row.item.editable ? 'editable' : ''"
v-model="row.item.firstName"
:readonly="!row.item.editable"
/>
</td>
<td>
<input
type="text"
:class="row.item.editable ? 'editable' : ''"
v-model="row.item.lastName"
:readonly="!row.item.editable"
/>
</td>
<td class="id-cell">
<input
type="text"
:class="row.item.editable ? 'editable' : ''"
v-model="row.item.staffId"
:readonly="!row.item.editable"
/>
</td>
<td class="email-cell">
<input
type="email"
:class="row.item.editable ? 'editable' : ''"
v-model="row.item.email"
:readonly="!row.item.editable"
/>
</td>
<td>
<input
type="tel"
:class="row.item.editable ? 'editable' : ''"
v-model="row.item.phone"
:readonly="!row.item.editable"
/>
</td>
<td>
<select
:class="row.item.editable ? 'editable' : ''"
:readonly="!row.item.editable"
v-model="row.item.role"
>
<option :value="row.item.role" selected>{{ row.item.role }}</option>
<option value="Driver">Driver</option>
<option value="Filler">Filler</option>
<option value="Shopware">Shopware</option>
</select>
</td>
<td class="text-center">
<CheckGreyIcon v-if="!row.item.status" />
<CheckGreenIcon v-else/>
</td>
<td>
<!-- dropdown start -->
<button
class="dropdown__trigger"
@click="toggleClass($event, accountUsersData.content.indexOf(row.item))"
:ref="`dropdown-${accountUsersData.content.indexOf(row.item)}`"
>
<PointsIcon />
</button>
<div
v-if="accountUsersData.content.indexOf(row.item) === selectedIndex"
class="dropdown"
v-click-outside="clickOutsideDropdown"
>
<div class="dropdown__inner">
<button
@click="row.item.editable ? updateAccountUser(row.item) : row.item.editable = true; clickOutsideDropdown()"
>
<template v-if="row.item.editable">Save fields</template>
<template v-else>Edit fields</template>
</button>
<div>
<button
@click="row.item.showPassword = !row.item.showPassword"
>
Change password
</button>
<form
v-if="row.item.showPassword"
@submit.prevent="changeAccountUserPassword(row.item)"
class="dropdown-form"
>
<input
class="dropdown-form__input"
placeholder="Old password"
type="password"
v-model="row.item.oldPassword"
>
<input
class="dropdown-form__input"
placeholder="New password"
type="password"
v-model="row.item.newPassword"
>
<button class="dropdown-form__submit" type="submit">Change</button>
</form>
</div>
<button
@click="!row.item.status ? enableAccountUser(row.item) : disableAccountUser(row.item)"
>
<template v-if="!row.item.status">Activate user</template>
<template v-else>Deactivate user</template>
</button>
<button
@click="resendAccountUserVerification(row.item)"
>
Re-send verification Email
</button>
<button
@click="removeAccountUser(row.item)"
>
Delete account
</button>
</div>
</div>
<!-- dropdown end -->
</td>
</tr>
</template>
</v-data-table>
<v-pagination
v-if="Math.ceil(accountUsersTotalCount / accountUsersPerPage) > 1"
class="top-50"
v-model="accountUsersCurrentPage"
:length="Math.ceil(accountUsersTotalCount / accountUsersPerPage)"
:total-visible="7"
@input="updateAccountUsersCurrentPage"
></v-pagination>
</client-only>
</v-card>
</div>
<!-- table end -->
</div>
<!-- lower end -->
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import debounce from 'lodash.debounce'
import PointsIcon from '~/assets/images/points.svg'
import CheckGreyIcon from '~/assets/images/check_grey.svg'
import CheckGreenIcon from '~/assets/images/check_green.svg'
export default {
components: {
PointsIcon,
CheckGreyIcon,
CheckGreenIcon,
},
data () {
return {
searchManagerValue: '',
selectedIndex: null,
}
},
computed: {
...mapGetters('account-users', [
'accountUsers',
'accountUsersLoading',
'accountUsersTotalCount',
'accountUsersCurrentPage',
'accountUsersPerPage',
'accountUsersSearch',
'enableAccountUserLoading',
'disableAccountUserLoading',
'resendAccountUserVerificationLoading',
]),
accountUsersData () {
const accountUsersData = {
headers: [
{ text: 'Name', sortable: false, align: 'start', value: 'firstName' },
{ text: 'Lastname', sortable: false, align: 'start', value: 'lastName' },
{ text: 'Staff-ID', sortable: false, value: 'id' },
{ text: 'E-Mail', sortable: false, value: 'email' },
{ text: 'Phone', sortable: false, value: 'phone' },
{ text: 'Job role', sortable: false, value: 'role' },
{ text: 'Status', sortable: false, align: 'center', value: 'status' },
{ text: '', sortable: false, value: 'settings' },
],
content: [],
}
if (this.accountUsers && this.accountUsers.length) {
this.accountUsers.forEach((user) => {
const userData = {
firstName: user.firstName,
lastName: user.lastName,
staffId: user.staffId,
email: user.username,
phone: user.phoneNumber,
role: user.roles[0],
editable: false,
status: user.enabled,
settings: '',
id: user._id,
oldPassword: '',
newPassword: '',
showPassword: false,
}
accountUsersData.content.push(userData)
})
}
return accountUsersData
},
},
async asyncData ({ store }) {
const params = {
page: store.state['account-users'].accountUsersCurrentPage,
perPage: store.state['account-users'].accountUsersPerPage,
search: store.state['account-users'].accountUsersSearch,
filter: 'Manager',
}
await store.dispatch('account-users/getAccountUsers', params)
if (store.state['account-users'].accountUsersSearch) {
return {
searchManagerValue: store.state['account-users'].accountUsersSearch,
}
}
},
methods: {
...mapActions('account-users', {
getAccountUsersAction: 'getAccountUsers',
updateAccountUsersCurrentPageAction: 'updateAccountUsersCurrentPage',
updateAccountUsersFilterAction: 'updateAccountUsersFilter',
updateAccountUsersSearchAction: 'updateAccountUsersSearch',
updateAccountUserAction: 'updateAccountUser',
enableAccountUserAction: 'enableAccountUser',
disableAccountUserAction: 'disableAccountUser',
changeAccountUserPasswordAction: 'changeAccountUserPassword',
removeAccountUserAction: 'removeAccountUser',
resendAccountUserVerificationAction: 'resendAccountUserVerification',
}),
getAccountUsers () {
const params = {
page: this.accountUsersCurrentPage,
perPage: this.accountUsersPerPage,
search: this.accountUsersSearch,
filter: 'Manager',
}
this.getAccountUsersAction(params)
},
updateAccountUsersCurrentPage(page){
this.updateAccountUsersCurrentPageAction(page)
this.getAccountUsers()
},
updateAccountUsersSearch(search) {
const that = this
debounce(() => {
that.updateAccountUsersCurrentPageAction(1)
that.updateAccountUsersSearchAction(search)
that.getAccountUsers()
}, 500)()
},
async updateAccountUser(data) {
try {
await this.updateAccountUserAction(data)
this.$notify({
type: 'success',
title: 'User successfully updated!',
})
data.editable = false
this.updateAccountUsersCurrentPageAction(1)
this.getAccountUsers()
} catch (err) {}
},
async removeAccountUser ({ id }) {
try {
await this.removeAccountUserAction({ id })
this.$notify({
type: 'success',
title: 'User successfully removed!',
})
} catch (err) {}
this.clickOutsideDropdown()
},
async enableAccountUser ({ id }) {
try {
await this.enableAccountUserAction({ id })
this.$notify({
type: 'success',
title: 'User successfully activated!',
})
} catch (err) {}
this.clickOutsideDropdown()
},
async disableAccountUser ({ id }) {
try {
await this.disableAccountUserAction({ id })
this.$notify({
type: 'success',
title: 'User successfully deactivated!',
})
} catch (err) {}
this.clickOutsideDropdown()
},
async changeAccountUserPassword (data) {
try {
await this.changeAccountUserPasswordAction(data)
this.$notify({
type: 'success',
title: 'Password successfully changed!',
})
data.oldPassword = ''
data.newPassword = ''
data.showPassword = false
} catch (err) {}
this.clickOutsideDropdown()
},
async resendAccountUserVerification ({ id }) {
try {
await this.resendAccountUserVerificationAction({ id })
this.$notify({
type: 'success',
title: 'Resend user verification!',
})
} catch (err) {}
this.clickOutsideDropdown()
},
toggleClass(event, index) {
if (!this.$refs[`dropdown-${index}`].classList.contains('dropdown__trigger--active')) {
this.$refs[`dropdown-${index}`].classList.value = 'dropdown__trigger--active'
this.selectedIndex = index
} else {
this.$refs[`dropdown-${index}`].classList.value = 'dropdown__trigger'
this.selectedIndex = null
}
},
clickOutsideDropdown() {
if (this.selectedIndex !== null) {
this.$refs[`dropdown-${this.selectedIndex}`].classList.value = 'dropdown__trigger'
this.selectedIndex = null
}
},
},
}
</script>
<style lang="scss" scoped>
.accounts-staff {
&__top {
display: flex;
justify-content: space-between;
align-items: center;
}
input,
select {
padding: 3px 0 0 0;
max-width: auto;
transition: color .3s;
border-bottom: 1px solid transparent;
}
td:last-of-type,
th:last-of-type {
padding: 8px 0;
}
input.editable,
select.editable {
color: #687584;
border-color:#ADB4C6;
transition: all .3s;
}
input.editable:focus {
border-color: #000;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment