236 lines
6.6 KiB
Vue
236 lines
6.6 KiB
Vue
<template>
|
|
<pn-page-template>
|
|
<template #title>
|
|
{{ $t(title) }}
|
|
</template>
|
|
<template #card-actions>
|
|
<q-btn
|
|
rounded color="primary"
|
|
class="w100 fix-disabled-btn"
|
|
:disable="!isFormValid"
|
|
@click = "onSubmit"
|
|
>
|
|
{{ $t(btnText) }}
|
|
</q-btn>
|
|
</template>
|
|
|
|
<div class="column items-center q-pa-md q-pb-sm">
|
|
<div class="relative-position flex justify-center w100 text-center">
|
|
<pn-auto-avatar
|
|
:img="userMod.photo"
|
|
:name="tname"
|
|
size="100px"
|
|
class="q-pb-lg"
|
|
:style="!userStatus ? {} : { filter: 'grayscale(100%)'}"
|
|
/>
|
|
<div
|
|
v-if="userStatus"
|
|
class="flex justify-center absolute-center w100 items-center"
|
|
>
|
|
<q-chip
|
|
square
|
|
:label="$t(userStatus.text)"
|
|
:color="userStatus.color"
|
|
text-color="white"
|
|
class="text-uppercase"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="flex row items-start justify-center no-wrap q-pb-lg">
|
|
<div class="flex column justify-center">
|
|
<div class="text-bold q-pr-xs text-center" align="center">{{ tname }}</div>
|
|
<div caption class="text-primary text-caption" align="center" v-if="user?.username">{{ user.username }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<q-form
|
|
ref="formRef"
|
|
@validation-success="isFormValid = true"
|
|
@validation-error="isFormValid = false"
|
|
class="q-gutter-y-lg w100"
|
|
>
|
|
<q-input
|
|
v-model.trim="userMod.fullname"
|
|
dense
|
|
filled
|
|
class = "w100 fix-bottom-padding"
|
|
:label = "$t('user_block__name')"
|
|
:rules="[inputRules.middleText]"
|
|
@update:model-value="formRef.validate()"
|
|
debounce="300"
|
|
/>
|
|
|
|
<q-select
|
|
v-model="userMod.company_id"
|
|
:options="displayCompanies"
|
|
dense
|
|
filled
|
|
class="w100 q-pt-sm"
|
|
:label = "$t('user_block__company')"
|
|
option-value="id"
|
|
emit-value
|
|
map-options
|
|
@update:model-value="formRef.validate()"
|
|
>
|
|
<template #option="scope">
|
|
<q-item v-bind="scope.itemProps">
|
|
<q-item-section avatar>
|
|
<pn-auto-avatar
|
|
v-if="scope.opt.id"
|
|
:img="scope.opt.logo"
|
|
:name="scope.opt.label"
|
|
size="md"
|
|
type="rounded"
|
|
/>
|
|
<q-avatar
|
|
v-else
|
|
rounded
|
|
size="md"
|
|
>
|
|
<q-icon size="32px" color="grey" name="mdi-cancel"/>
|
|
</q-avatar>
|
|
</q-item-section>
|
|
<q-item-section>
|
|
<q-item-label>{{ scope.opt.label }}</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
</template>
|
|
</q-select>
|
|
|
|
<q-input
|
|
v-model.trim="userMod.department"
|
|
dense
|
|
filled
|
|
class = "w100 fix-bottom-padding q-pt-sm"
|
|
:label = "$t('user_block__department')"
|
|
:rules="[inputRules.middleText]"
|
|
@update:model-value="formRef.validate()"
|
|
debounce="300"
|
|
/>
|
|
|
|
<q-input
|
|
v-model.trim="userMod.role"
|
|
dense
|
|
filled
|
|
class = "w100 fix-bottom-padding q-pt-sm"
|
|
:label = "$t('user_block__role')"
|
|
:rules="[inputRules.middleText]"
|
|
@update:model-value="formRef.validate()"
|
|
debounce="300"
|
|
/>
|
|
|
|
<q-input
|
|
v-model.trim="userMod.phone"
|
|
dense
|
|
filled
|
|
class = "w100 fix-bottom-padding q-pt-sm"
|
|
:rules="[inputRules.middleText]"
|
|
@update:model-value="formRef.validate()"
|
|
debounce="300"
|
|
>
|
|
<template #prepend>
|
|
<q-icon name="mdi-phone-outline"/>
|
|
</template>
|
|
</q-input>
|
|
|
|
<q-input
|
|
v-model.trim="userMod.email"
|
|
dense
|
|
filled
|
|
class = "w100 fix-bottom-padding q-pt-sm"
|
|
:rules="[inputRules.middleText]"
|
|
@update:model-value="formRef.validate()"
|
|
debounce="300"
|
|
>
|
|
<template #prepend>
|
|
<q-icon name="mdi-email-outline"/>
|
|
</template>
|
|
</q-input>
|
|
</q-form>
|
|
</div>
|
|
</pn-page-template>
|
|
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, reactive, onMounted } from 'vue'
|
|
import { useCompaniesStore } from 'stores/companies'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useInputRules } from 'composables/useInputRules'
|
|
import { removeNullKeys, getFieldValue } from 'utils/helpers'
|
|
import { getUserStatus } from 'utils/users'
|
|
import type { User } from 'types/User'
|
|
|
|
const { t } = useI18n()
|
|
const { inputRules } = useInputRules()
|
|
|
|
const props = defineProps<{
|
|
title: string,
|
|
btnText: string,
|
|
user?: User
|
|
}>()
|
|
|
|
const emit = defineEmits(['update'])
|
|
|
|
const userMod = reactive({
|
|
fullname: props.user?.fullname ?? '',
|
|
company_id: props.user?.company_id ?? null,
|
|
department: props.user?.department ?? '',
|
|
role: props.user?.role ?? '',
|
|
phone: props.user?.phone ?? '',
|
|
email: props.user?.email ?? '',
|
|
photo: props.user?.photo ?? null
|
|
})
|
|
|
|
const companiesStore = useCompaniesStore()
|
|
const companies = computed(() => companiesStore.companies)
|
|
|
|
const displayCompanies = computed(() => [
|
|
...companies.value.map(el => ({
|
|
id: el.id,
|
|
label: el.name,
|
|
logo: el.logo
|
|
})),
|
|
{
|
|
id: null,
|
|
label: t('user_block__no_company'),
|
|
logo: ''
|
|
}
|
|
])
|
|
|
|
const tname = computed(() =>
|
|
[props.user?.firstname, props.user?.lastname]
|
|
.filter(Boolean)
|
|
.join(' ')
|
|
)
|
|
|
|
const userStatus = computed(() => props.user ? getUserStatus(props.user) : null)
|
|
|
|
const formRef = ref()
|
|
const isFormValid = ref(false)
|
|
|
|
function onSubmit() {
|
|
const outData = {
|
|
fullname: getFieldValue(userMod.fullname, props.user?.fullname),
|
|
company_id: userMod.company_id,
|
|
department: getFieldValue(userMod.department, props.user?.department),
|
|
role: getFieldValue(userMod.role, props.user?.role),
|
|
phone: getFieldValue(userMod.phone, props.user?.phone),
|
|
email: getFieldValue(userMod.email, props.user?.email),
|
|
}
|
|
emit('update', removeNullKeys(outData, ['company_id']))
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await formRef.value.validate()
|
|
if (!isFormValid.value) formRef.value.resetValidation()
|
|
})
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.fix-bottom-padding.q-field--with-bottom {
|
|
padding-bottom: 0 !important
|
|
}
|
|
</style>
|