304 lines
8.7 KiB
Vue
304 lines
8.7 KiB
Vue
<template>
|
|
<div class="account-new no-margin">
|
|
<h1 class="title is-1" v-t="'account.create'"></h1>
|
|
<form @submit.prevent="submitAccount">
|
|
<div class="columns is-multiline is-centered">
|
|
<div class="column is-two-thirds">
|
|
<h3 class="subtitle is-3">Nom</h3>
|
|
<div class="field">
|
|
<div class="control">
|
|
<input
|
|
type="text"
|
|
class="input"
|
|
maxlength="30"
|
|
v-model="name"
|
|
required
|
|
/>
|
|
</div>
|
|
<p class="help is-primary">
|
|
{{
|
|
$tc('validation.max_char', 30 - name.length, {
|
|
max: 30 - name.length
|
|
})
|
|
}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="column is-two-thirds">
|
|
<h3 class="subtitle is-3" v-t="'account.main_currency'"></h3>
|
|
<div class="control">
|
|
<div class="select is-fullwidth">
|
|
<select
|
|
name="main-currency"
|
|
id="main-currency"
|
|
v-model="mainCurrency"
|
|
>
|
|
<option v-for="(cur, k) in currencies" :key="k" :value="cur"
|
|
>{{ cur.name }} {{ cur.symbol }}</option
|
|
>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-two-thirds">
|
|
<h3 class="subtitle is-3">Compte privé / public</h3>
|
|
<div class="field">
|
|
<input
|
|
id="is-public"
|
|
type="checkbox"
|
|
name="is-public"
|
|
class="switch"
|
|
v-model="isPublic"
|
|
/>
|
|
<label for="is-public">{{ isPublic ? 'public' : 'privé' }}</label>
|
|
<p
|
|
class="help is-primary"
|
|
v-t="
|
|
isPublic
|
|
? 'account.publicInformation'
|
|
: 'account.privateInformation'
|
|
"
|
|
></p>
|
|
</div>
|
|
</div>
|
|
<div class="column is-two-thirds">
|
|
<color-picker v-model="color" />
|
|
</div>
|
|
<div class="column is-two-thirds">
|
|
<account-user-new v-model="users" />
|
|
</div>
|
|
<div class="column is-two-thirds">
|
|
<h3 class="subtitle is-3 title-currency" @click="toggleCurrencyShow">
|
|
<div class="icon-container">
|
|
<awe-icon
|
|
icon="chevron-right"
|
|
:rotation="currencyShow ? 90 : undefined"
|
|
/>
|
|
</div>
|
|
{{
|
|
$tc('account.used_currencies', accountCurrencies.length, {
|
|
count: accountCurrencies.length
|
|
})
|
|
}}
|
|
</h3>
|
|
<transition name="fade">
|
|
<div class="currency-list" v-if="currencyShow">
|
|
<div class="field">
|
|
<div class="columns no-margin is-multiline">
|
|
<div
|
|
class="column is-half"
|
|
v-for="(currency, k) in currencies"
|
|
:key="k"
|
|
>
|
|
<input
|
|
class="is-checkradio is-block is-medium"
|
|
type="checkbox"
|
|
:name="`cur-${currency.code}`"
|
|
:id="`cur-${currency.code}`"
|
|
v-model="accountCurrencies"
|
|
:value="currency"
|
|
:disabled="currency.code === mainCurrency.code"
|
|
/>
|
|
<label :for="`cur-${currency.code}`"
|
|
>{{ currency.name }} ({{
|
|
currency.symbol || currency.code
|
|
}})</label
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</div>
|
|
</div>
|
|
<div class="columns is-centered">
|
|
<div class="column is-two-thirds">
|
|
<button type="submit" class="button is-primary is-fullwidth is-large">
|
|
<awe-icon icon="check" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
|
import { Getter } from 'vuex-class'
|
|
import currencies from '@/data/currencies'
|
|
import IAccount from '@/models/IAccount'
|
|
import ICurrency from '@/models/ICurrency'
|
|
import accountService from '@/services/AccountService'
|
|
import queueNotifService from '@/services/QueueNotifService'
|
|
import IUser from '@/models/IUser'
|
|
import { slug } from '@/utils'
|
|
|
|
@Component({
|
|
components: {
|
|
'color-picker': () => import('@/components/ColorPicker.vue'),
|
|
'account-user-new': () => import('@/components/AccountUserNew.vue')
|
|
}
|
|
})
|
|
export default class AccountNew extends Vue {
|
|
@Getter
|
|
public user!: IUser | null
|
|
public name: string = ''
|
|
public currencies: ICurrency[] = currencies
|
|
public mainCurrency: ICurrency = currencies[0]
|
|
public accountCurrencies: ICurrency[] = [currencies[0]]
|
|
public color: string | null = null
|
|
public users: IUser[] = []
|
|
public currencyShow: boolean = false
|
|
public isPublic: boolean = false
|
|
|
|
public mounted(): void {
|
|
if (this.user && !this.user.alias) {
|
|
this.user.alias = this.user.userId
|
|
}
|
|
}
|
|
|
|
public toggleCurrencyShow(): void {
|
|
this.currencyShow = !this.currencyShow
|
|
}
|
|
|
|
public validate(users: IUser[]): boolean {
|
|
if (!this.name) {
|
|
queueNotifService.error('Le nom doit être rempli.')
|
|
return false
|
|
}
|
|
const aliases: string[] = users.map((user: IUser) =>
|
|
user.alias ? user.alias.toLowerCase() : ''
|
|
)
|
|
if (aliases.length === 0) {
|
|
queueNotifService.error(
|
|
'Au moins une personne doit être ajoutée au compte.'
|
|
)
|
|
return false
|
|
}
|
|
if (aliases.length !== new Set(aliases).size) {
|
|
queueNotifService.error('Les alias doivent être uniques.')
|
|
return false
|
|
}
|
|
|
|
if (this.user) {
|
|
const userIds: string[] = users.map((user: IUser) => user.userId)
|
|
if (userIds.length !== new Set(userIds).size) {
|
|
queueNotifService.error('Les identifiants doivent être uniques.')
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
public async submitAccount(): Promise<void> {
|
|
let users: IUser[] = this.user ? [this.user, ...this.users] : this.users
|
|
if (!this.validate(users)) {
|
|
return
|
|
}
|
|
users = users.map((u: IUser) => ({
|
|
userId: u.userId,
|
|
email: u.email,
|
|
slugEmail: u.slugEmail,
|
|
premium: u.premium,
|
|
alias: u.alias,
|
|
firstname: u.firstname,
|
|
lastname: u.lastname
|
|
}))
|
|
const userIds: string[] = users.map((u: IUser) => slug(u.userId))
|
|
const newAccount: IAccount = {
|
|
doctype: 'account',
|
|
name: this.name,
|
|
admin: this.user
|
|
? {
|
|
userId: this.user.userId,
|
|
email: this.user.email,
|
|
slugEmail: this.user.slugEmail,
|
|
premium: this.user.premium,
|
|
alias: this.user.alias,
|
|
firstname: this.user.firstname,
|
|
lastname: this.user.lastname
|
|
}
|
|
: null,
|
|
color: this.color,
|
|
users,
|
|
userIds,
|
|
mainCurrency: this.mainCurrency,
|
|
currencies: this.accountCurrencies,
|
|
isPublic: this.isPublic
|
|
}
|
|
const response: PouchDB.Core.Response = await accountService.add(newAccount)
|
|
if (response.ok) {
|
|
this.$router.push({ name: 'account', params: { id: response.id } })
|
|
} else {
|
|
// tslint:disable-next-line:no-console
|
|
console.warn(response)
|
|
queueNotifService.error(
|
|
`Une erreur s'est produite à la création d'un compte.`
|
|
)
|
|
}
|
|
}
|
|
|
|
@Watch('mainCurrency', { immediate: true })
|
|
public onMainCurrencyChange(
|
|
currency: ICurrency,
|
|
oldCurrency: ICurrency
|
|
): void {
|
|
if (oldCurrency) {
|
|
this.accountCurrencies = this.accountCurrencies.filter(
|
|
(c: ICurrency) => c.code !== oldCurrency.code
|
|
)
|
|
}
|
|
const cur: ICurrency | undefined = this.currencies.find(
|
|
(c: ICurrency) => c.code === currency.code
|
|
)
|
|
if (cur) {
|
|
const already: ICurrency | undefined = this.accountCurrencies.find(
|
|
(c: ICurrency) => c.code === cur.code
|
|
)
|
|
if (!already) {
|
|
this.accountCurrencies.push(cur)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '~bulma-switch';
|
|
|
|
h3 {
|
|
max-width: 400px;
|
|
margin: auto;
|
|
}
|
|
.icon-container {
|
|
float: left;
|
|
|
|
svg {
|
|
transition: transform 0.3s cubic-bezier(0.55, 0, 0.1, 1);
|
|
}
|
|
}
|
|
.title-currency {
|
|
&:hover {
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
.currency-list {
|
|
margin-top: 10px;
|
|
max-height: 50vh;
|
|
overflow-y: auto;
|
|
}
|
|
.fade-enter-active,
|
|
.fade-leave-active {
|
|
transition: opacity 0.3s cubic-bezier(0.55, 0, 0.1, 1),
|
|
transform 0.3s cubic-bezier(0.55, 0, 0.1, 1);
|
|
}
|
|
|
|
.fade-enter,
|
|
.fade-leave-to {
|
|
opacity: 0;
|
|
transform: translateY(-50px);
|
|
}
|
|
</style>
|
|
|