feat: AccountDescriptor

This commit is contained in:
Javier Segarra 2024-06-05 15:09:43 +02:00
parent 30c912fa62
commit de488169b7
7 changed files with 139 additions and 132 deletions

View File

@ -67,6 +67,7 @@ async function confirm() {
</QCardSection> </QCardSection>
<QCardSection class="row items-center"> <QCardSection class="row items-center">
<span v-html="message"></span> <span v-html="message"></span>
<slot name="customHTML"></slot>
</QCardSection> </QCardSection>
<QCardActions align="right"> <QCardActions align="right">
<QBtn <QBtn

View File

@ -7,6 +7,8 @@ import VnLv from 'src/components/ui/VnLv.vue';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
import AccountDescriptorMenu from './AccountDescriptorMenu.vue'; import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
import FetchData from 'src/components/FetchData.vue';
const $props = defineProps({ const $props = defineProps({
id: { id: {
type: Number, type: Number,
@ -68,8 +70,7 @@ const hasAccount = ref(false);
</QBtn> </QBtn>
</template> </template>
<template #menu> <template #menu>
{{}} <AccountDescriptorMenu :has-account="hasAccount" />
<AccountDescriptorMenu />
</template> </template>
<template #before> <template #before>
<QImg :src="getAccountAvatar()" class="photo"> <QImg :src="getAccountAvatar()" class="photo">
@ -95,28 +96,6 @@ const hasAccount = ref(false);
</template> </template>
<template #actions="{ entity }"> <template #actions="{ entity }">
<QCardActions class="q-gutter-x-md"> <QCardActions class="q-gutter-x-md">
<QIcon
v-if="entity.hasAccount"
color="primary"
name="contact_mail"
flat
round
size="sm"
class="fill-icon"
>
<QTooltip>{{ t('account.card.enabled') }}</QTooltip>
</QIcon>
<QIcon
v-if="!entity.hasAccount"
color="primary"
name="contact_mail"
flat
round
size="sm"
class="fill-icon"
>
<QTooltip>{{ t('account.card.disabled') }}</QTooltip>
</QIcon>
<QIcon <QIcon
v-if="!entity.active" v-if="!entity.active"
color="primary" color="primary"
@ -128,6 +107,17 @@ const hasAccount = ref(false);
> >
<QTooltip>{{ t('account.card.deactivated') }}</QTooltip> <QTooltip>{{ t('account.card.deactivated') }}</QTooltip>
</QIcon> </QIcon>
<QIcon
color="primary"
name="contact_mail"
v-if="entity.hasAccount"
flat
round
size="sm"
class="fill-icon"
>
<QTooltip>{{ t('account.card.enabled') }}</QTooltip>
</QIcon>
</QCardActions> </QCardActions>
</template> </template>
</CardDescriptor> </CardDescriptor>

View File

@ -1,73 +1,109 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { computed, ref } from 'vue'; import { computed, ref, toRefs } from 'vue';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { usePrintService } from 'composables/usePrintService';
import { useVnConfirm } from 'composables/useVnConfirm'; import { useVnConfirm } from 'composables/useVnConfirm';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import CustomerChangePassword from 'src/pages/Customer/components/CustomerChangePassword.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
const quasar = useQuasar(); const quasar = useQuasar();
const $props = defineProps({
hasAccount: {
type: Boolean,
default: false,
required: true,
},
});
const { t } = useI18n(); const { t } = useI18n();
const { openReport } = usePrintService(); const { hasAccount } = toRefs($props);
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const route = useRoute(); const route = useRoute();
const account = computed(() => useArrayData('AccountId').store.data[0]); const account = computed(() => useArrayData('AccountId').store.data[0]);
const entityId = computed(() => route.params.id); account.value.hasAccount = hasAccount.value;
const entityId = computed(() => +route.params.id);
async function setPassword() { async function updateStatusAccount(active) {
await axios.post(`Accounts`, { id: entityId }); if (active) {
} await axios.post(`Accounts`, { id: entityId.value });
async function enableAccount() { } else {
await axios.post(`Accounts`, { id: entityId }); await axios.delete(`Accounts/${entityId.value}`);
account.value.hasAccount = true; }
account.value.hasAccount = active;
const status = active ? 'enable' : 'disable';
quasar.notify({ quasar.notify({
message: t('globals.dataSaved'), message: t(`account.card.${status}Account.success`),
type: 'positive', type: 'positive',
}); });
} }
async function disableAccount() { async function updateStatusUser(active) {
await axios.post(`Accounts`, { id: entityId }); await axios.patch(`VnUsers/${entityId.value}`, { active });
account.value.hasAccount = false; account.value.active = active;
const status = active ? 'activate' : 'deactivate';
quasar.notify({ quasar.notify({
message: t('globals.dataSaved'), message: t(`account.card.actions.${status}User.success`),
type: 'positive', type: 'positive',
}); });
} }
async function activateUser() { function setPassword() {
await axios.patch(`VnUsers/${entityId.value}`, { active: true }); quasar.dialog({
account.value.active = true; component: CustomerChangePassword,
// quasar.notify({ componentProps: {
// message: t('globals.dataSaved'), id: entityId.value,
// type: 'positive', },
// }); });
} }
async function deactivateUser() { const showSyncDialog = ref(false);
await axios.patch(`VnUsers/${entityId.value}`, { active: false }); const syncPassword = ref(null);
account.value.active = false; const shouldSyncPassword = ref(false);
// quasar.notify({ async function sync() {
// message: t('globals.dataSaved'), const params = { force: true };
// type: 'positive', if (shouldSyncPassword.value) params.password = syncPassword.value;
// }); await axios.patch(`Accounts/${account.value.name}/sync`, {
params,
});
quasar.notify({
message: t('account.card.actions.sync.success'),
type: 'positive',
});
} }
</script> </script>
<template> <template>
{{ account }} <VnConfirm
<QItem v-model="showSyncDialog"
v-ripple :message="t('account.card.actions.sync.message')"
clickable :title="t('account.card.actions.sync.title')"
@click=" :promise="sync"
openConfirmationModal(
t('Confirm deletion'),
t('Are you sure...TODO'),
setPassword
)
"
> >
<template #customHTML>
{{ shouldSyncPassword }}
<QCheckbox
:label="t('account.card.actions.sync.checkbox')"
v-model="shouldSyncPassword"
class="full-width"
clearable
clear-icon="close"
>
<QIcon style="padding-left: 10px" color="primary" name="info" size="sm">
<QTooltip>{{ t('account.card.actions.sync.tooltip') }}</QTooltip>
</QIcon></QCheckbox
>
<QInput
v-if="shouldSyncPassword"
:label="t('login.password')"
v-model="syncPassword"
class="full-width"
clearable
clear-icon="close"
type="password"
/>
</template>
</VnConfirm>
<QItem v-ripple clickable @click="setPassword">
<QItemSection>{{ t('account.card.actions.setPassword') }}</QItemSection> <QItemSection>{{ t('account.card.actions.setPassword') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem
@ -78,7 +114,7 @@ async function deactivateUser() {
openConfirmationModal( openConfirmationModal(
t('account.card.actions.enableAccount.title'), t('account.card.actions.enableAccount.title'),
t('account.card.actions.enableAccount.subtitle'), t('account.card.actions.enableAccount.subtitle'),
enableAccount () => updateStatusAccount(true)
) )
" "
> >
@ -92,12 +128,27 @@ async function deactivateUser() {
openConfirmationModal( openConfirmationModal(
t('account.card.actions.disableAccount.title'), t('account.card.actions.disableAccount.title'),
t('account.card.actions.disableAccount.subtitle'), t('account.card.actions.disableAccount.subtitle'),
disableAccount () => updateStatusAccount(false)
) )
" "
> >
<QItemSection>{{ t('account.card.actions.disableAccount.name') }}</QItemSection> <QItemSection>{{ t('account.card.actions.disableAccount.name') }}</QItemSection>
</QItem> </QItem>
<QItem
v-if="!account.active"
v-ripple
clickable
@click="
openConfirmationModal(
t('account.card.actions.activateUser.title'),
t('account.card.actions.activateUser.title'),
() => updateStatusUser(true)
)
"
>
<QItemSection>{{ t('account.card.actions.activateUser.name') }}</QItemSection>
</QItem>
<QItem <QItem
v-if="account.active" v-if="account.active"
v-ripple v-ripple
@ -106,37 +157,13 @@ async function deactivateUser() {
openConfirmationModal( openConfirmationModal(
t('account.card.actions.deactivateUser.title'), t('account.card.actions.deactivateUser.title'),
t('account.card.actions.deactivateUser.title'), t('account.card.actions.deactivateUser.title'),
deactivateUser () => updateStatusUser(false)
) )
" "
> >
<QItemSection>{{ t('account.card.actions.deactivateUser.name') }}</QItemSection> <QItemSection>{{ t('account.card.actions.deactivateUser.name') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem v-ripple clickable @click="showSyncDialog = true">
v-if="!account.active"
v-ripple
clickable
@click="
openConfirmationModal(
t('account.card.actions.activateUser.title'),
t('account.card.actions.activateUser.title'),
activateUser
)
"
>
<QItemSection>{{ t('account.card.actions.activateUser.name') }}</QItemSection>
</QItem>
<QItem
v-ripple
clickable
@click="
openConfirmationModal(
t('account.card.actions.sync.title'),
t('account.card.actions.sync.subtitle'),
sync
)
"
>
<QItemSection>{{ t('account.card.actions.sync.name') }}</QItemSection> <QItemSection>{{ t('account.card.actions.sync.name') }}</QItemSection>
</QItem> </QItem>
@ -158,24 +185,3 @@ async function deactivateUser() {
<QItemSection>{{ t('account.card.actions.delete.name') }}</QItemSection> <QItemSection>{{ t('account.card.actions.delete.name') }}</QItemSection>
</QItem> </QItem>
</template> </template>
<i18n>
{
"en": {
"pickupOrder": "Pickup order",
"openPickupOrder": "Open pickup order",
"sendPickupOrder": "Send pickup order",
"deleteAccount": "Delete account",
"confirmDeletion": "Confirm deletion",
"confirmDeletionMessage": "Are you sure you want to delete this account?"
},
"es": {
"pickupOrder": "Orden de recogida",
"openPickupOrder": "Abrir orden de recogida",
"sendPickupOrder": "Enviar orden de recogida",
"deleteAccount": "Eliminar reclamación",
"confirmDeletion": "Confirmar eliminación",
"confirmDeletionMessage": "Seguro que quieres eliminar esta reclamación?"
}
}
</i18n>

View File

@ -40,26 +40,35 @@ account:
name: Disable account name: Disable account
title: The account will be disabled title: The account will be disabled
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: 'Account disabled!'
enableAccount: enableAccount:
name: Enable account name: Enable account
title: The account will be enabled title: The account will be enabled
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: 'Account enabled!'
deactivateUser: deactivateUser:
name: Deactivate user name: Deactivate user
title: The user will be deactivated title: The user will be deactivated
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: 'User deactivated!'
activateUser: activateUser:
name: Activate user name: Activate user
title: The user will be disabled title: The user will be disabled
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: 'User activated!'
sync: sync:
name: Sync name: Sync
title: The account will be sync title: The account will be sync
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: 'User synchronized!'
checkbox: Synchronize password
message: Do you want to synchronize user?
tooltip: If password is not specified, just user attributes are synchronized
delete: delete:
name: Delete name: Delete
title: The account will be deleted title: The account will be deleted
subtitle: Are you sure you want to continue? subtitle: Are you sure you want to continue?
success: ''
search: Search user search: Search user
searchInfo: You can search by id, name or nickname searchInfo: You can search by id, name or nickname
create: create:

View File

@ -39,26 +39,35 @@ account:
name: Deshabilitar cuenta name: Deshabilitar cuenta
title: La cuenta será deshabilitada title: La cuenta será deshabilitada
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: '¡Cuenta deshabilitada!'
enableAccount: enableAccount:
name: Habilitar cuenta name: Habilitar cuenta
title: La cuenta será habilitada title: La cuenta será habilitada
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: '¡Cuenta habilitada!'
deactivateUser: deactivateUser:
name: Desactivar usuario name: Desactivar usuario
title: El usuario será deshabilitado title: El usuario será deshabilitado
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: '¡Usuario desactivado!'
activateUser: activateUser:
name: Activar usuario name: Activar usuario
title: El usuario será activado title: El usuario será activado
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: '¡Usuario activado!'
sync: sync:
name: Sincronizar name: Sincronizar
title: El usuario será sincronizado title: El usuario será sincronizado
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: '¡Usuario sincronizado!'
checkbox: Sincronizar contraseña
message: ¿Quieres sincronizar el usuario?
tooltip: Si la contraseña no se especifica solo se sincronizarán lo atributos del usuario
delete: delete:
name: Eliminar name: Eliminar
title: El usuario será eliminado title: El usuario será eliminado
subtitle: ¿Seguro que quieres continuar? subtitle: ¿Seguro que quieres continuar?
success: ''
search: Buscar usuario search: Buscar usuario
searchInfo: Puedes buscar por id, nombre o usuario searchInfo: Puedes buscar por id, nombre o usuario
create: create:

View File

@ -28,7 +28,6 @@ const isLoading = ref(false);
const name = ref(null); const name = ref(null);
const usersPreviewRef = ref(null); const usersPreviewRef = ref(null);
const user = ref([]); const user = ref([]);
const userPasswords = ref(0);
const dataChanges = computed(() => { const dataChanges = computed(() => {
return ( return (
@ -45,7 +44,6 @@ const showChangePasswordDialog = () => {
component: CustomerChangePassword, component: CustomerChangePassword,
componentProps: { componentProps: {
id: route.params.id, id: route.params.id,
userPasswords: userPasswords.value,
promise: usersPreviewRef.value.fetch(), promise: usersPreviewRef.value.fetch(),
}, },
}); });
@ -97,11 +95,6 @@ const onSubmit = async () => {
@on-fetch="(data) => (canChangePassword = data)" @on-fetch="(data) => (canChangePassword = data)"
auto-load auto-load
/> />
<FetchData
@on-fetch="(data) => (userPasswords = data[0])"
auto-load
url="UserPasswords"
/>
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()"> <Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
<QBtnGroup push class="q-gutter-x-sm"> <QBtnGroup push class="q-gutter-x-sm">

View File

@ -9,6 +9,7 @@ import useNotify from 'src/composables/useNotify';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import FetchData from 'src/components/FetchData.vue';
const { dialogRef } = useDialogPluginComponent(); const { dialogRef } = useDialogPluginComponent();
const { notify } = useNotify(); const { notify } = useNotify();
@ -19,15 +20,12 @@ const $props = defineProps({
type: String, type: String,
required: true, required: true,
}, },
userPasswords: {
type: Object,
required: true,
},
promise: { promise: {
type: Function, type: Function,
required: true, required: true,
}, },
}); });
const userPasswords = ref({});
const closeButton = ref(null); const closeButton = ref(null);
const isLoading = ref(false); const isLoading = ref(false);
@ -60,6 +58,11 @@ const onSubmit = async () => {
<template> <template>
<QDialog ref="dialogRef"> <QDialog ref="dialogRef">
<FetchData
@on-fetch="(data) => (userPasswords = data[0])"
auto-load
url="UserPasswords"
/>
<QCard class="q-pa-lg"> <QCard class="q-pa-lg">
<QCardSection> <QCardSection>
<QForm @submit.prevent="onSubmit"> <QForm @submit.prevent="onSubmit">
@ -71,7 +74,7 @@ const onSubmit = async () => {
<QIcon name="close" size="sm" /> <QIcon name="close" size="sm" />
</span> </span>
<VnRow class="row q-gutter-md q-mb-md"> <VnRow class="row q-gutter-md q-mb-md" style="flex-direction: column">
<div class="col"> <div class="col">
<VnInput <VnInput
:label="t('New password')" :label="t('New password')"
@ -84,11 +87,7 @@ const onSubmit = async () => {
<QTooltip> <QTooltip>
{{ {{
t('customer.card.passwordRequirements', { t('customer.card.passwordRequirements', {
length: $props.userPasswords.length, ...userPasswords,
nAlpha: $props.userPasswords.nAlpha,
nDigits: $props.userPasswords.nDigits,
nPunct: $props.userPasswords.nPunct,
nUpper: $props.userPasswords.nUpper,
}) })
}} }}
</QTooltip> </QTooltip>