admin-fe/src/views/invites/index.vue

320 lines
8.7 KiB
Vue

<template>
<div class="invites-container">
<h1>{{ $t('invites.inviteTokens') }}</h1>
<div class="actions-container">
<el-button class="create-invite-token" @click="createTokenDialogVisible = true">
<span>
<i class="icon el-icon-plus"/>
{{ $t('invites.createInviteToken') }}
</span>
</el-button>
<el-button class="invite-via-email" @click="inviteUserDialogVisible = true">
<span>
<i class="icon el-icon-message"/>
{{ $t('invites.inviteUserViaEmail') }}
</span>
</el-button>
</div>
<el-dialog
:visible.sync="createTokenDialogVisible"
:show-close="false"
:title="$t('invites.createInviteToken')"
custom-class="create-new-token-dialog">
<el-form ref="newTokenForm" :model="newTokenForm" :label-width="getLabelWidth" status-icon>
<el-form-item :label="$t('invites.maxUse')">
<el-input-number
v-model="newTokenForm.maxUse"
:min="0"
:size="isDesktop ? 'medium' : 'small'"
name="maxUse"/>
</el-form-item>
<el-form-item :label="$t('invites.expiresAt')">
<el-date-picker
v-model="newTokenForm.expiresAt"
:placeholder="$t('invites.pickDate')"
class="pick-date"
type="date"
name="date"
value-format="yyyy-MM-dd"/>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="closeDialogWindow">{{ $t('invites.cancel') }}</el-button>
<el-button type="primary" @click="createToken">{{ $t('invites.create') }}</el-button>
</span>
<el-card v-if="'token' in newToken">
<div slot="header" class="clearfix">
<span>{{ $t('invites.tokenCreated') }}</span>
</div>
<p>{{ this.$t('invites.token') }}: {{ newToken.token }}</p>
<p>{{ this.$t('invites.maxUse') }}: {{ newToken.maxUse }}</p>
<p>{{ this.$t('invites.expiresAt') }}: {{ newToken.expiresAt }}</p>
</el-card>
</el-dialog>
<el-dialog
:visible.sync="inviteUserDialogVisible"
:show-close="false"
:title="$t('invites.sendRegistration')"
custom-class="invite-via-email-dialog">
<div>
<p class="info">{{ $t('invites.inviteViaEmailAlert') }}</p>
<el-form ref="inviteUserForm" :model="inviteUserForm" :rules="rules" :label-width="getLabelWidth" status-icon>
<el-form-item :label="$t('invites.email')" prop="email">
<el-input v-model="inviteUserForm.email" name="email" type="email" autofocus/>
</el-form-item>
<el-form-item :label="$t('invites.name')" prop="name">
<el-input v-model="inviteUserForm.name" name="name"/>
</el-form-item>
</el-form>
</div>
<span slot="footer">
<el-button @click="closeDialogWindow">{{ $t('invites.cancel') }}</el-button>
<el-button type="primary" @click="inviteUserViaEmail">{{ $t('invites.create') }}</el-button>
</span>
</el-dialog>
<el-table
v-loading="loading"
:data="tokens"
:default-sort = "{prop: 'used', order: 'ascending'}"
class="invite-token-table">
<el-table-column
v-if="isDesktop"
:label="$t('invites.id')"
min-width="60"
prop="id"
sortable/>
<el-table-column
:label="$t('invites.token')"
:min-width="isDesktop ? 350 : 125"
prop="token"/>
<el-table-column
v-if="isDesktop"
:label="$t('invites.expiresAt')"
align="center"
header-align="center"
min-width="110"
prop="expires_at"
sortable/>
<el-table-column
:label="$t('invites.maxUse')"
align="center"
header-align="center"
min-width="60"
prop="max_use"
sortable/>
<el-table-column
v-if="isDesktop"
:label="$t('invites.uses')"
align="center"
header-align="center"
min-width="60"
prop="uses"/>
<el-table-column
:label="$t('invites.used')"
:min-width="isDesktop ? 60 : 50"
align="center"
header-align="center"
prop="used"
sortable>
<template slot-scope="scope">
<el-tag
:type="scope.row.used ? 'danger' : 'success'"
disable-transitions>{{ scope.row.used ? $t('invites.used') : $t('invites.active') }}</el-tag>
</template>
</el-table-column>
<el-table-column
:label="$t('invites.actions')"
:min-width="isDesktop ? 100 : 50"
align="center"
header-align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click.native="revokeInviteToken(scope.row.token)">
{{ $t('invites.revoke') }}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
rules: {
email: [
{ validator: this.validateEmail, trigger: 'blur' }
]
},
newTokenForm: {
maxUse: 1,
expiresAt: ''
},
inviteUserForm: {
email: '',
name: ''
},
createTokenDialogVisible: false,
inviteUserDialogVisible: false
}
},
computed: {
getLabelWidth() {
return this.isDesktop ? '100px' : '80px'
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
loading() {
return this.$store.state.invites.loading
},
newToken() {
return this.$store.state.invites.newToken
},
tokens() {
return this.$store.state.invites.inviteTokens
}
},
mounted() {
this.$store.dispatch('FetchInviteTokens')
},
methods: {
closeDialogWindow() {
this.inviteUserDialogVisible = false
this.createTokenDialogVisible = false
this.$store.dispatch('RemoveNewToken')
this.$data.inviteUserForm.email = ''
this.$data.inviteUserForm.name = ''
},
createToken() {
this.$store.dispatch('GenerateInviteToken', this.$data.newTokenForm)
},
async inviteUserViaEmail() {
this.$refs['inviteUserForm'].validate(async(valid) => {
if (valid) {
await this.$store.dispatch('InviteUserViaEmail', this.$data.inviteUserForm)
this.closeDialogWindow()
} else {
this.$message({
type: 'error',
message: this.$t('invites.submitFormError')
})
return false
}
})
},
revokeInviteToken(token) {
this.$store.dispatch('RevokeToken', token)
},
validateEmail(rule, value, callback) {
if (value === '') {
return callback(new Error(this.$t('invites.emptyEmailError')))
} else if (!this.validEmail(value)) {
return callback(new Error(this.$t('invites.invalidEmailError')))
} else {
return callback()
}
},
validEmail(email) {
const re = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
return re.test(email)
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
.invites-container {
.actions-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 20px 15px 15px 15px;
}
.create-invite-token {
text-align: left;
width: 350px;
padding: 10px;
}
.create-new-token-dialog {
width: 40%
}
.el-dialog__body {
padding: 5px 20px 0 20px
}
h1 {
margin: 22px 0 0 15px;
}
.icon {
margin-right: 5px;
}
.invite-token-table {
width: 100%;
margin: 0 15px;
}
.invite-via-email {
text-align: left;
width: 350px;
padding: 10px;
}
.invite-via-email-dialog {
width: 50%
}
.info {
color: #666666;
font-size: 13px;
line-height: 22px;
margin: 0 0 10px 0;
}
}
@media
only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
.invites-container {
.actions-container {
display: flex;
height: 82px;
flex-direction: column;
align-items: center;
margin: 15px 10px 7px 10px;
}
.create-invite-token {
width: 100%;
}
.create-new-token-dialog {
width: 85%
}
.el-date-editor {
width: 150px;
}
.el-dialog__body {
padding: 5px 15px 0 15px
}
h1 {
margin: 7px 10px 15px 10px;
}
.invite-token-table {
width: 100%;
margin: 0;
}
.invite-via-email {
width: 100%;
margin: 10px 0 0 0;
}
.invite-via-email-dialog {
width: 85%
}
.info {
margin: 0 0 10px 5px;
}
}
.create-invite-token {
width: 100%
}
.invite-via-email {
width: 100%
}
}
</style>