WIP on monterail_vue3_migration_frontend--vee-validate-refactor

This commit is contained in:
Kamila 2024-08-08 09:44:31 +02:00
parent 4b7423a314
commit 2e6d62f274
10 changed files with 670 additions and 564 deletions

156
frontend/components.d.ts vendored Normal file
View File

@ -0,0 +1,156 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AmountAndNameRow: typeof import('./src/components/TransactionRows/AmountAndNameRow.vue')['default']
AuthCarousel: typeof import('./src/components/Auth/AuthCarousel.vue')['default']
AuthFooter: typeof import('./src/components/Auth/AuthFooter.vue')['default']
AuthNavbar: typeof import('./src/components/Auth/AuthNavbar.vue')['default']
AuthNavbarSmall: typeof import('./src/components/Auth/AuthNavbarSmall.vue')['default']
BAvatar: typeof import('bootstrap-vue-next')['BAvatar']
BBadge: typeof import('bootstrap-vue-next')['BBadge']
BButton: typeof import('bootstrap-vue-next')['BButton']
BCard: typeof import('bootstrap-vue-next')['BCard']
BCardBody: typeof import('bootstrap-vue-next')['BCardBody']
BCardText: typeof import('bootstrap-vue-next')['BCardText']
BCardTitle: typeof import('bootstrap-vue-next')['BCardTitle']
BCarousel: typeof import('bootstrap-vue-next')['BCarousel']
BCarouselSlide: typeof import('bootstrap-vue-next')['BCarouselSlide']
BCol: typeof import('bootstrap-vue-next')['BCol']
BCollapse: typeof import('bootstrap-vue-next')['BCollapse']
BContainer: typeof import('bootstrap-vue-next')['BContainer']
BDropdown: typeof import('bootstrap-vue-next')['BDropdown']
BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem']
BForm: typeof import('bootstrap-vue-next')['BForm']
BFormCheckbox: typeof import('bootstrap-vue-next')['BFormCheckbox']
BFormGroup: typeof import('bootstrap-vue-next')['BFormGroup']
BFormInput: typeof import('bootstrap-vue-next')['BFormInput']
BFormInvalidFeedback: typeof import('bootstrap-vue-next')['BFormInvalidFeedback']
BFormSelect: typeof import('bootstrap-vue-next')['BFormSelect']
BImg: typeof import('bootstrap-vue-next')['BImg']
BInputGroup: typeof import('bootstrap-vue-next')['BInputGroup']
BLink: typeof import('bootstrap-vue-next')['BLink']
BModal: typeof import('bootstrap-vue-next')['BModal']
BNav: typeof import('bootstrap-vue-next')['BNav']
BNavbar: typeof import('bootstrap-vue-next')['BNavbar']
BNavbarBrand: typeof import('bootstrap-vue-next')['BNavbarBrand']
BNavbarNav: typeof import('bootstrap-vue-next')['BNavbarNav']
BNavItem: typeof import('bootstrap-vue-next')['BNavItem']
BPopover: typeof import('bootstrap-vue-next')['BPopover']
Breadcrumb: typeof import('./src/components/Breadcrumb/breadcrumb.vue')['default']
BRow: typeof import('bootstrap-vue-next')['BRow']
BTab: typeof import('bootstrap-vue-next')['BTab']
BTabs: typeof import('bootstrap-vue-next')['BTabs']
BToastOrchestrator: typeof import('bootstrap-vue-next')['BToastOrchestrator']
ClipboardCopy: typeof import('./src/components/ClipboardCopy.vue')['default']
CollapseIcon: typeof import('./src/components/TransactionRows/CollapseIcon.vue')['default']
CollapseLinksList: typeof import('./src/components/DecayInformations/CollapseLinksList.vue')['default']
CommunityMember: typeof import('./src/components/Template/ContentHeader/CommunityMember.vue')['default']
CommunityNews: typeof import('./src/components/Overview/CommunityNews.vue')['default']
CommunitySwitch: typeof import('./src/components/CommunitySwitch.vue')['default']
ContentFooter: typeof import('./src/components/ContentFooter.vue')['default']
ContributionForm: typeof import('./src/components/Contributions/ContributionForm.vue')['default']
ContributionInfo: typeof import('./src/components/Template/RightSide/ContributionInfo.vue')['default']
ContributionList: typeof import('./src/components/Contributions/ContributionList.vue')['default']
ContributionListItem: typeof import('./src/components/Contributions/ContributionListItem.vue')['default']
ContributionMessagesFormular: typeof import('./src/components/ContributionMessages/ContributionMessagesFormular.vue')['default']
ContributionMessagesList: typeof import('./src/components/ContributionMessages/ContributionMessagesList.vue')['default']
ContributionMessagesListItem: typeof import('./src/components/ContributionMessages/ContributionMessagesListItem.vue')['default']
DateRow: typeof import('./src/components/TransactionRows/DateRow.vue')['default']
DecayInformation: typeof import('./src/components/DecayInformations/DecayInformation.vue')['default']
DecayInformationBeforeStartblock: typeof import('./src/components/DecayInformations/DecayInformation-BeforeStartblock.vue')['default']
DecayInformationDecay: typeof import('./src/components/DecayInformations/DecayInformation-Decay.vue')['default']
DecayInformationDecayStartblock: typeof import('./src/components/DecayInformations/DecayInformation-DecayStartblock.vue')['default']
DecayInformationLong: typeof import('./src/components/DecayInformations/DecayInformation-Long.vue')['default']
DecayInformationShort: typeof import('./src/components/DecayInformations/DecayInformation-Short.vue')['default']
DecayRow: typeof import('./src/components/TransactionRows/DecayRow.vue')['default']
DurationRow: typeof import('./src/components/TransactionRows/DurationRow.vue')['default']
FigureQrCode: typeof import('./src/components/QrCode/FigureQrCode.vue')['default']
FirstName: typeof import('./src/components/Inputs/FirstName.vue')['default']
GddAmount: typeof import('./src/components/Template/ContentHeader/GddAmount.vue')['default']
GddSend: typeof import('./src/components/GddSend.vue')['default']
GddTransactionList: typeof import('./src/components/GddTransactionList.vue')['default']
GddTransactionListFooter: typeof import('./src/components/GddTransactionListFooter.vue')['default']
GdtAmount: typeof import('./src/components/Template/ContentHeader/GdtAmount.vue')['default']
GdtTransactionList: typeof import('./src/components/GdtTransactionList.vue')['default']
IBiBellFill: typeof import('~icons/bi/bell-fill')['default']
IBiCaretDownFill: typeof import('~icons/bi/caret-down-fill')['default']
IBiCheck: typeof import('~icons/bi/check')['default']
IBiEye: typeof import('~icons/bi/eye')['default']
IBiEyeSlash: typeof import('~icons/bi/eye-slash')['default']
IBiLayers: typeof import('~icons/bi/layers')['default']
IBiPeople: typeof import('~icons/bi/people')['default']
IBiQuestion: typeof import('~icons/bi/question')['default']
IBiTrash: typeof import('~icons/bi/trash')['default']
IBiXCircle: typeof import('~icons/bi/x-circle')['default']
InputAmount: typeof import('./src/components/Inputs/InputAmount.vue')['default']
InputEmail: typeof import('./src/components/Inputs/InputEmail.vue')['default']
InputHour: typeof import('./src/components/Inputs/InputHour.vue')['default']
InputIdentifier: typeof import('./src/components/Inputs/InputIdentifier.vue')['default']
InputPassword: typeof import('./src/components/Inputs/InputPassword.vue')['default']
InputPasswordConfirmation: typeof import('./src/components/Inputs/InputPasswordConfirmation.vue')['default']
InputTextarea: typeof import('./src/components/Inputs/InputTextarea.vue')['default']
InputUsername: typeof import('./src/components/Inputs/InputUsername.vue')['default']
LanguageSwitch: typeof import('./src/components/LanguageSwitch.vue')['default']
LanguageSwitch2: typeof import('./src/components/LanguageSwitch2.vue')['default']
LanguageSwitchSelect: typeof import('./src/components/LanguageSwitchSelect.vue')['default']
LastContributions: typeof import('./src/components/Template/RightSide/LastContributions.vue')['default']
LastName: typeof import('./src/components/Inputs/LastName.vue')['default']
LastTransactions: typeof import('./src/components/Template/RightSide/LastTransactions.vue')['default']
LinkCountRow: typeof import('./src/components/TransactionRows/LinkCountRow.vue')['default']
MemoRow: typeof import('./src/components/TransactionRows/MemoRow.vue')['default']
Message: typeof import('./src/components/Message/Message.vue')['default']
MobileSidebar: typeof import('./src/components/MobileSidebar/MobileSidebar.vue')['default']
Name: typeof import('./src/components/TransactionRows/Name.vue')['default']
Navbar: typeof import('./src/components/Menu/Navbar.vue')['default']
NavCommunity: typeof import('./src/components/Template/ContentHeader/NavCommunity.vue')['default']
OpenCreationsAmount: typeof import('./src/components/Contributions/OpenCreationsAmount.vue')['default']
Overview: typeof import('./src/components/skeleton/Overview.vue')['default']
ParseMessage: typeof import('./src/components/ContributionMessages/ParseMessage.vue')['default']
RedeemedTextBox: typeof import('./src/components/LinkInformations/RedeemedTextBox.vue')['default']
RedeemInformation: typeof import('./src/components/LinkInformations/RedeemInformation.vue')['default']
RedeemLoggedOut: typeof import('./src/components/LinkInformations/RedeemLoggedOut.vue')['default']
RedeemSelfCreator: typeof import('./src/components/LinkInformations/RedeemSelfCreator.vue')['default']
RedeemValid: typeof import('./src/components/LinkInformations/RedeemValid.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SessionLogoutTimeout: typeof import('./src/components/SessionLogoutTimeout.vue')['default']
Sidebar: typeof import('./src/components/Menu/Sidebar.vue')['default']
Status: typeof import('./src/components/Status.vue')['default']
Transaction: typeof import('./src/components/Transaction.vue')['default']
TransactionCollapse: typeof import('./src/components/TransactionCollapse.vue')['default']
TransactionConfirmationLink: typeof import('./src/components/GddSend/TransactionConfirmationLink.vue')['default']
TransactionConfirmationSend: typeof import('./src/components/GddSend/TransactionConfirmationSend.vue')['default']
TransactionCreation: typeof import('./src/components/Transactions/TransactionCreation.vue')['default']
TransactionDecay: typeof import('./src/components/Transactions/TransactionDecay.vue')['default']
TransactionForm: typeof import('./src/components/GddSend/TransactionForm.vue')['default']
TransactionLink: typeof import('./src/components/TransactionLinks/TransactionLink.vue')['default']
TransactionLinkItem: typeof import('./src/components/TransactionLinkItem.vue')['default']
TransactionLinkSummary: typeof import('./src/components/Transactions/TransactionLinkSummary.vue')['default']
TransactionListItem: typeof import('./src/components/TransactionListItem.vue')['default']
TransactionReceive: typeof import('./src/components/Transactions/TransactionReceive.vue')['default']
TransactionResultLink: typeof import('./src/components/GddSend/TransactionResultLink.vue')['default']
TransactionResultSendError: typeof import('./src/components/GddSend/TransactionResultSendError.vue')['default']
TransactionResultSendSuccess: typeof import('./src/components/GddSend/TransactionResultSendSuccess.vue')['default']
TransactionSend: typeof import('./src/components/Transactions/TransactionSend.vue')['default']
TypeIcon: typeof import('./src/components/TransactionRows/TypeIcon.vue')['default']
UserCard: typeof import('./src/components/UserSettings/UserCard.vue')['default']
UserData: typeof import('./src/components/UserSettings/UserData.vue')['default']
UserGMSLocation: typeof import('./src/components/UserSettings/UserGMSLocation.vue')['default']
UserGMSLocationFormat: typeof import('./src/components/UserSettings/UserGMSLocationFormat.vue')['default']
UserLanguage: typeof import('./src/components/UserSettings/UserLanguage.vue')['default']
UserName: typeof import('./src/components/UserSettings/UserName.vue')['default']
UserNamingFormat: typeof import('./src/components/UserSettings/UserNamingFormat.vue')['default']
UserNewsletter: typeof import('./src/components/UserSettings/UserNewsletter.vue')['default']
UserPassword: typeof import('./src/components/UserSettings/UserPassword.vue')['default']
UserSettingsSwitch: typeof import('./src/components/UserSettings/UserSettingsSwitch.vue')['default']
}
export interface ComponentCustomProperties {
vBToggle: typeof import('bootstrap-vue-next')['vBToggle']
}
}

View File

@ -27,6 +27,8 @@
<BFormGroup :label="label" :label-for="labelFor">
<BFormInput
v-bind="ariaInput"
:modelValue="currentValue"
@update:modelValue="currentValue"
:id="labelFor"
:model-value="currentValue"
:name="name"

View File

@ -19,7 +19,8 @@
:immediate="true"
:name="createId(register ? $t('form.password') : $t('form.password_new'))"
:placeholder="register ? $t('form.password') : $t('form.password_new')"
></input-password>
v-model="password"
/>
</BCol>
</BRow>
<BRow class="mb-2">
@ -35,52 +36,40 @@
:immediate="true"
:name="createId(register ? $t('form.passwordRepeat') : $t('form.password_new_repeat'))"
:placeholder="register ? $t('form.passwordRepeat') : $t('form.password_new_repeat')"
></input-password>
v-model="passwordRepeat"
/>
</BCol>
</BRow>
</div>
</template>
<script>
<script setup>
import { computed, ref, watch } from 'vue'
import InputPassword from './InputPassword'
import { BCol, BRow } from 'bootstrap-vue-next'
export default {
name: 'InputPasswordConfirm',
components: {
InputPassword,
const password = ref('')
const passwordRepeat = ref('')
defineProps({
value: {
type: Object,
required: true,
},
props: {
value: {
type: Object,
required: true,
},
register: {
type: Boolean,
required: false,
},
},
data() {
return {
password: '',
passwordRepeat: '',
}
},
computed: {
passwordObject() {
return { password: this.password, passwordRepeat: this.passwordRepeat }
},
},
watch: {
password() {
this.$emit('input', this.passwordObject)
},
passwordRepeat() {
this.$emit('input', this.passwordObject)
},
},
methods: {
createId(text) {
return text.replace(/ +/g, '-')
},
register: {
type: Boolean,
required: false,
},
})
const createId = (text) => {
return text.replace(/ +/g, '-')
}
const passwordObject = computed(() => {
return { password: password.value, passwordRepeat: passwordRepeat.value }
})
watch([password, passwordRepeat], () => {
emit('input', passwordObject.value)
})
</script>

View File

@ -1,18 +1,11 @@
<template>
<div class="input-username">
<validation-provider
v-slot="{ errors, valid, validated, ariaInput, ariaMsg }"
tag="div"
:rules="rules"
:name="name"
:bails="!showAllErrors"
:immediate="immediate"
vid="username"
>
<b-form-group :label="$t('form.username')" :description="$t('settings.usernameInfo')">
<b-input-group>
<b-form-input
<div>
<BFormGroup :label="$t('form.username')" :description="$t('settings.usernameInfo')">
<BInputGroup>
<BFormInput
v-bind="ariaInput"
v-model="currentValue"
:id="labelFor"
v-model="currentValue"
:name="name"
@ -21,20 +14,12 @@
:state="validated ? valid : false"
autocomplete="off"
data-test="username"
></b-form-input>
<b-input-group-append>
<b-button
size="lg"
text="Button"
variant="secondary"
icon="x-lg"
@click="$emit('set-is-edit', false)"
>
<b-icon-x-circle></b-icon-x-circle>
</b-button>
</b-input-group-append>
</b-input-group>
<b-form-invalid-feedback v-bind="ariaMsg">
/>
<BButton size="lg" text="Button" variant="secondary" @click="emitSetIsEdit" append>
<IBiXCircle style="height: 17px; width: 17px" />
</BButton>
</BInputGroup>
<BFormInvalidFeedback v-bind="ariaMsg">
<div v-if="showAllErrors">
<span v-for="error in errors" :key="error">
{{ error }}
@ -42,48 +27,51 @@
</span>
</div>
<div v-else>
{{ errors[0] }}
<!-- {{ errors?.[0] }} -->
</div>
</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</BFormInvalidFeedback>
</BFormGroup>
</div>
</div>
</template>
<script>
export default {
name: 'InputUsername',
props: {
isEdit: { type: Boolean, default: false },
rules: {
default: () => {
return {
required: true,
}
},
type: () => {},
},
name: { type: String, default: 'username' },
label: { type: String, default: 'Username' },
placeholder: { type: String, default: 'Username' },
value: { required: true, type: String },
showAllErrors: { type: Boolean, default: false },
immediate: { type: Boolean, default: false },
unique: { type: Boolean, required: true },
},
data() {
return {
currentValue: this.value,
}
},
computed: {
labelFor() {
return this.name + '-input-field'
},
},
watch: {
currentValue() {
this.$emit('input', this.currentValue)
},
},
<script setup>
import {
BFormGroup,
BInputGroup,
BFormInput,
BButton,
BFormInvalidFeedback,
} from 'bootstrap-vue-next'
import { ref, computed, watch, defineProps, defineEmits } from 'vue'
import { useForm } from 'vee-validate'
const props = defineProps({
isEdit: { type: Boolean, default: false },
rules: { type: Object, default: () => ({ required: true }) },
name: { type: String, default: 'username' },
label: { type: String, default: 'Username' },
placeholder: { type: String, default: 'Username' },
value: { type: String, required: true },
showAllErrors: { type: Boolean, default: false },
immediate: { type: Boolean, default: false },
unique: { type: Boolean, required: true },
})
const currentValue = ref(props?.value)
const { errors, valid, validated, ariaInput, ariaMsg } = useForm({
initialValues: currentValue.value,
})
const emit = defineEmits(['input', 'set-is-edit'])
const labelFor = computed(() => `${props.name}-input-field`)
const emitSetIsEdit = (bool) => {
emit('set-is-edit', bool)
}
watch(currentValue, (newValue) => {
emit('input', newValue)
})
</script>

View File

@ -1,117 +1,113 @@
<template>
<div id="username_form">
<div v-if="$store.state.username">
<div v-if="store.state.username">
<label>{{ $t('form.username') }}</label>
<b-form-group
<BFormGroup
class="mb-3"
data-test="username-input-group"
:description="$t('settings.emailInfo')"
>
<b-form-input
v-model="username"
readonly
data-test="username-input-readonly"
></b-form-input>
</b-form-group>
<BFormInput v-model="username" readonly data-test="username-input-readonly" />
</BFormGroup>
</div>
<div v-else>
<validation-observer ref="usernameObserver" v-slot="{ handleSubmit, invalid }">
<b-form @submit.stop.prevent="handleSubmit(onSubmit)">
<BRow class="mb-3">
<BCol class="col-12">
<input-username
v-model="username"
:name="$t('form.username')"
:placeholder="$t('form.username-placeholder')"
:show-all-errors="true"
:unique="true"
:rules="rules"
:is-edit="isEdit"
data-test="component-input-username"
@set-is-edit="setIsEdit"
/>
</BCol>
<BCol class="col-12">
<div v-if="!username" class="alert" data-test="username-alert">
{{ $t('settings.username.no-username') }}
</div>
</BCol>
</BRow>
<BRow v-if="newUsername" class="text-right">
<BCol>
<div ref="submitButton" class="text-right">
<b-button
:variant="disabled(invalid) ? 'light' : 'success'"
type="submit"
:disabled="disabled(invalid)"
data-test="submit-username-button"
>
{{ $t('form.save') }}
</b-button>
</div>
</BCol>
</BRow>
</b-form>
</validation-observer>
<!-- <validation-observer ref="usernameObserver" v-slot="{ handleSubmit, invalid }">-->
<div>
<!-- <BForm @submit.stop.prevent="handleSubmit(onSubmit)"> -->
<BRow class="mb-3">
<BCol class="col-12">
<input-username
v-model="username"
:name="$t('form.username')"
:placeholder="$t('form.username-placeholder')"
:showAllErrors="true"
:unique="true"
:rules="rules"
:isEdit="isEdit"
@set-is-edit="setIsEdit"
data-test="component-input-username"
/>
</BCol>
<BCol class="col-12">
<div v-if="!username" class="alert" data-test="username-alert">
{{ $t('settings.username.no-username') }}
</div>
</BCol>
</BRow>
<BRow class="text-right" v-if="newUsername">
<BCol>
<div class="text-right" ref="submitButton">
<BButton
:variant="disabled(invalid) ? 'light' : 'success'"
type="submit"
:disabled="disabled(invalid)"
data-test="submit-username-button"
>
{{ $t('form.save') }}
</BButton>
</div>
</BCol>
</BRow>
<!-- </BForm> -->
</div>
<!-- </validation-observer> -->
</div>
</div>
</template>
<script>
import { updateUserInfos } from '@/graphql/mutations'
import InputUsername from '@/components/Inputs/InputUsername'
export default {
name: 'UserName',
components: {
InputUsername,
},
data() {
return {
isEdit: false,
username: this.$store.state.username || '',
usernameUnique: false,
rules: {
required: true,
min: 3,
max: 20,
usernameAllowedChars: true,
usernameHyphens: true,
usernameUnique: true,
},
}
},
computed: {
newUsername() {
return this.username !== this.$store.state.username
},
},
methods: {
async onSubmit(event) {
this.$apollo
.mutate({
mutation: updateUserInfos,
variables: {
alias: this.username,
},
})
.then(() => {
this.$store.commit('username', this.username)
this.toastSuccess(this.$t('settings.username.change-success'))
})
.catch((error) => {
this.toastError(error.message)
})
},
disabled(invalid) {
return !this.newUsername || invalid
},
setIsEdit(bool) {
this.username = this.$store.state.username
this.isEdit = bool
},
},
<script setup>
import { ref, computed } from 'vue'
import { useStore } from 'vuex'
import { useMutation } from '@vue/apollo-composable'
import { BRow, BCol, BFormInput, BFormGroup, BForm, BButton } from 'bootstrap-vue-next'
import InputUsername from '@/components/Inputs/InputUsername'
import { updateUserInfos } from '@/graphql/mutations'
import { useAppToast } from '@/composables/useToast'
import { useForm } from 'vee-validate'
const store = useStore()
const { toastError, toastSuccess } = useAppToast()
const isEdit = ref(false)
const username = ref(store.state.username || '')
const usernameUnique = ref(false)
const rules = {
required: true,
min: 3,
max: 20,
usernameAllowedChars: true,
usernameHyphens: true,
usernameUnique: true,
}
const { handleSubmit, invalid } = useForm({
initialValues: username.value,
})
const { mutate: updateUserInfo } = useMutation(updateUserInfos)
const onSubmit = async () => {
try {
await updateUserInfo({ alias: username.value })
store.commit('username', username.value)
toastSuccess(t('settings.username.change-success'))
} catch (error) {
toastError(error.message)
}
}
const disabled = (invalid) => {
return !newUsername.value || invalid
}
const setIsEdit = (bool) => {
username.value = store.state.username
isEdit.value = bool
}
const newUsername = computed(() => username.value !== store.state.username)
</script>
<style>
.cursor-pointer {
cursor: pointer;

View File

@ -1,8 +1,8 @@
<template>
<div class="user-naming-format">
<b-dropdown v-model="selectedOption">
<BDropdown v-model="selectedOption">
<template #button-content>{{ selectedOptionLabel }}</template>
<b-dropdown-item
<BDropdownItem
v-for="option in dropdownOptions"
:key="option.value"
:value="option.value"
@ -10,82 +10,83 @@
@click.prevent="update(option)"
>
{{ option.label }}
</b-dropdown-item>
</b-dropdown>
</BDropdownItem>
</BDropdown>
</div>
</template>
<script>
import { updateUserInfos } from '@/graphql/mutations'
export default {
name: 'UserNamingFormat',
props: {
initialValue: { type: String, default: 'PUBLISH_NAME_ALIAS_OR_INITALS' },
attrName: { type: String },
successMessage: { type: String },
<script setup>
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { useMutation } from '@vue/apollo-composable'
import { updateUserInfos } from '@/graphql/mutations'
import { BDropdownItem, BDropdown } from 'bootstrap-vue-next'
import { useAppToast } from '@/composables/useToast'
const { t } = useI18n()
const store = useStore()
const { toastError } = useAppToast()
const props = defineProps({
initialValue: { type: String, default: 'PUBLISH_NAME_ALIAS_OR_INITALS' },
attrName: { type: String },
successMessage: { type: String },
})
const emit = defineEmits(['valueChanged'])
const selectedOption = ref(props.initialValue)
const dropdownOptions = [
{
label: t('settings.publish-name.alias-or-initials'),
title: t('settings.publish-name.alias-or-initials-tooltip'),
value: 'PUBLISH_NAME_ALIAS_OR_INITALS',
},
data() {
return {
selectedOption: this.initialValue,
dropdownOptions: [
{
label: this.$t('settings.publish-name.alias-or-initials'),
title: this.$t('settings.publish-name.alias-or-initials-tooltip'),
value: 'PUBLISH_NAME_ALIAS_OR_INITALS',
},
{
label: this.$t('settings.publish-name.initials'),
title: this.$t('settings.publish-name.initials-tooltip'),
value: 'PUBLISH_NAME_INITIALS',
},
{
label: this.$t('settings.publish-name.first'),
title: this.$t('settings.publish-name.first-tooltip'),
value: 'PUBLISH_NAME_FIRST',
},
{
label: this.$t('settings.publish-name.first-initial'),
title: this.$t('settings.publish-name.first-initial-tooltip'),
value: 'PUBLISH_NAME_FIRST_INITIAL',
},
{
label: this.$t('settings.publish-name.name-full'),
title: this.$t('settings.publish-name.name-full-tooltip'),
value: 'PUBLISH_NAME_FULL',
},
],
}
{
label: t('settings.publish-name.initials'),
title: t('settings.publish-name.initials-tooltip'),
value: 'PUBLISH_NAME_INITIALS',
},
computed: {
selectedOptionLabel() {
const selected = this.dropdownOptions.find(
(option) => option.value === this.selectedOption,
).label
return selected || this.$t('settings.publish-name.alias-or-initials')
// return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
},
{
label: t('settings.publish-name.first'),
title: t('settings.publish-name.first-tooltip'),
value: 'PUBLISH_NAME_FIRST',
},
methods: {
async update(option) {
if (option.value === this.selectedOption) {
return
}
try {
const variables = []
variables[this.attrName] = option.value
await this.$apollo.mutate({
mutation: updateUserInfos,
variables,
})
this.toastSuccess(this.successMessage)
this.selectedOption = option.value
this.$store.commit(this.attrName, option.value)
this.$emit('valueChanged', option.value)
} catch (error) {
this.toastError(error.message)
}
},
{
label: t('settings.publish-name.first-initial'),
title: t('settings.publish-name.first-initial-tooltip'),
value: 'PUBLISH_NAME_FIRST_INITIAL',
},
{
label: t('settings.publish-name.name-full'),
title: t('settings.publish-name.name-full-tooltip'),
value: 'PUBLISH_NAME_FULL',
},
]
const selectedOptionLabel = computed(() => {
const selected = dropdownOptions.find((option) => option.value === selectedOption.value)?.label
return selected || t('settings.publish-name.alias-or-initials')
})
const { mutate: updateUserData } = useMutation(updateUserInfos)
const update = async (option) => {
if (option.value === selectedOption.value) {
return
}
try {
const variables = {}
variables[props.attrName] = option.value
await updateUserData({ variables })
toastSuccess(props.successMessage)
selectedOption.value = option.value
store.commit(props.attrName, option.value)
emit('valueChanged', option.value)
} catch (error) {
toastError(error.message)
}
}
</script>
<style>

View File

@ -1,43 +1,45 @@
<template>
<div class="formusernewsletter">
<b-form-checkbox
<BFormCheckbox
test="BFormCheckbox"
v-model="newsletterState"
test="BFormCheckbox"
name="check-button"
switch
@change="onSubmit"
></b-form-checkbox>
/>
</div>
</template>
<script>
<script setup>
import { ref } from 'vue'
import { useStore } from 'vuex'
import { subscribeNewsletter, unsubscribeNewsletter } from '@/graphql/mutations'
import { useMutation } from '@vue/apollo-composable'
import { BFormCheckbox } from 'bootstrap-vue-next'
import { useAppToast } from '@/composables/useToast'
export default {
name: 'UserNewsletter',
data() {
return {
newsletterState: this.$store.state.newsletterState,
}
},
methods: {
async onSubmit() {
this.$apollo
.mutate({
mutation: this.newsletterState ? subscribeNewsletter : unsubscribeNewsletter,
})
.then(() => {
this.$store.commit('newsletterState', this.newsletterState)
this.toastSuccess(
this.newsletterState
? this.$t('settings.newsletter.newsletterTrue')
: this.$t('settings.newsletter.newsletterFalse'),
)
})
.catch((error) => {
this.newsletterState = this.$store.state.newsletterState
this.toastError(error.message)
})
},
},
const { toastSuccess, toastError } = useAppToast()
const store = useStore()
const state = store.state
const newsletterState = ref(state.newsletterState)
const { mutate: newsletterSubscribe } = useMutation(subscribeNewsletter)
const { mutate: newsletterUnsubscribe } = useMutation(unsubscribeNewsletter)
const onSubmit = async () => {
try {
newsletterState.value ? newsletterSubscribe() : newsletterUnsubscribe()
store.commit('newsletterState', newsletterState.value)
toastSuccess(
newsletterState.value
? $t('settings.newsletter.newsletterTrue')
: $t('settings.newsletter.newsletterFalse'),
)
} catch (error) {
newsletterState.value = state.newsletterState
toastError(error.message)
}
}
</script>

View File

@ -1,113 +1,102 @@
<template>
<b-card id="change_pwd" class="card-border-radius card-background-gray">
<BCard id="change_pwd" class="card-border-radius card-background-gray">
<div>
<BRow class="mb-4 text-right">
<BCol class="text-right">
<a
class="cursor-pointer"
data-test="open-password-change-form"
@click="showPassword ? (showPassword = !showPassword) : cancelEdit()"
>
<button @click="toggleShowPassword" data-test="open-password-change-form">
<span class="pointer mr-3">{{ $t('settings.password.change-password') }}</span>
<b-icon v-if="showPassword" class="pointer ml-3" icon="pencil"></b-icon>
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
</a>
<!-- <b-icon v-if="showPassword" class="pointer ml-3" icon="pencil"></b-icon>
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon> -->
</button>
</BCol>
</BRow>
</div>
<div v-if="!showPassword">
<validation-observer ref="observer" v-slot="{ handleSubmit, invalid }">
<b-form @submit.stop.prevent="handleSubmit(onSubmit)">
<BRow class="mb-2">
<BCol>
<input-password
v-model="form.password"
:label="$t('form.password_old')"
:placeholder="$t('form.password_old')"
></input-password>
</BCol>
</BRow>
<input-password-confirmation v-model="form.newPassword" :register="register" />
<BRow class="text-right">
<BCol>
<div class="text-right">
<b-button
type="submit"
:variant="invalid ? 'light' : 'success'"
class="mt-4"
:disabled="invalid && disabled"
data-test="submit-new-password-btn"
>
{{ $t('form.save') }}
</b-button>
</div>
</BCol>
</BRow>
</b-form>
</validation-observer>
<BForm @submit.prevent="onSubmit">
<BRow class="mb-2">
<BCol>
<input-password
:label="$t('form.password_old')"
:placeholder="$t('form.password_old')"
v-model="form.password"
/>
</BCol>
</BRow>
<input-password-confirmation v-model="form.newPassword" :register="register" />
<BRow class="text-right">
<BCol>
<div class="text-right">
<BButton
type="submit"
:variant="invalid ? 'light' : 'success'"
class="mt-4"
:disabled="invalid && disabled"
data-test="submit-new-password-btn"
>
{{ $t('form.save') }}
</BButton>
</div>
</BCol>
</BRow>
</BForm>
</div>
</b-card>
</BCard>
</template>
<script>
<script setup>
import { ref, computed } from 'vue'
import { BRow, BCol, BForm, BButton } from 'bootstrap-vue-next'
import InputPassword from '@/components/Inputs/InputPassword'
import InputPasswordConfirmation from '@/components/Inputs/InputPasswordConfirmation'
import { updateUserInfos } from '@/graphql/mutations'
import { useForm } from 'vee-validate'
import { useMutation } from '@vue/apollo-composable'
import { useAppToast } from '@/composables/useToast'
export default {
name: 'UserPassword',
components: {
InputPassword,
InputPasswordConfirmation,
},
data() {
return {
showPassword: true,
email: null,
form: {
password: '',
newPassword: {
password: '',
passwordRepeat: '',
},
},
register: false,
}
},
computed: {
disabled() {
return this.form.newPassword.password !== this.form.newPassword.passwordRepeat
},
},
methods: {
cancelEdit() {
this.showPassword = true
this.form.password = ''
this.form.passwordNew = ''
this.form.passwordNewRepeat = ''
},
async onSubmit() {
this.$apollo
.mutate({
mutation: updateUserInfos,
variables: {
password: this.form.password,
passwordNew: this.form.newPassword.password,
},
})
.then(() => {
this.toastSuccess(this.$t('message.reset'))
this.cancelEdit()
})
.catch((error) => {
this.toastError(error.message)
})
},
const showPassword = ref(true)
const email = ref(null)
const register = ref(false)
const form = ref({
password: '',
newPassword: {
password: '',
passwordRepeat: '',
},
})
const { toastError, toastSuccess } = useAppToast()
const { handleSubmit, invalid } = useForm({
initialValues: form.value,
})
const disabled = computed(() => {
return form.value.newPassword.password !== form.value.newPassword.passwordRepeat
})
const cancelEdit = () => {
showPassword.value = true
form.value.password = ''
form.value.passwordNew = ''
form.value.passwordNewRepeat = ''
}
const toggleShowPassword = () => {
showPassword.value ? (showPassword.value = !showPassword.value) : cancelEdit()
}
const { mutate: updateUserInfo } = useMutation(updateUserInfos)
const onSubmit = handleSubmit(async () => {
try {
await updateUserInfo({
password: form.value.password,
passwordNew: form.value.newPassword.password,
})
toastSuccess($t('message.reset'))
cancelEdit()
} catch (error) {
toastError(error.message)
}
})
</script>
<style>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -1,59 +1,64 @@
<template>
<div class="form-user-switch" @click="onClick">
<b-form-checkbox
v-model="value"
<!-- <BFormCheckbox
test="BFormCheckbox"
name="check-button"
:disabled="disabled"
switch
@change="onChange"
></b-form-checkbox>
/> -->
hello
</div>
</template>
<script>
<script setup>
import { useStore } from 'vuex'
import { ref } from 'vue'
import { updateUserInfos } from '@/graphql/mutations'
import { useMutation } from '@vue/apollo-composable'
import { BFormCheckbox } from 'bootstrap-vue-next'
import { useAppToast } from '@/composables/useToast'
export default {
name: 'UserSettingsSwitch',
props: {
initialValue: { type: Boolean, default: false },
attrName: { type: String },
enabledText: { type: String },
disabledText: { type: String },
disabled: { type: Boolean, default: false },
notAllowedText: { type: String, default: undefined },
},
emits: ['value-changed'],
data() {
return {
value: this.initialValue,
}
},
methods: {
async onChange() {
if (this.isDisabled) return
const variables = []
variables[this.attrName] = this.value
this.$apollo
.mutate({
mutation: updateUserInfos,
variables,
})
.then(() => {
this.$store.commit(this.attrName, this.value)
this.$emit('value-changed', this.value)
this.toastSuccess(this.value ? this.enabledText : this.disabledText)
})
.catch((error) => {
this.value = this.initialValue
this.toastError(error.message)
})
},
onClick() {
if (this.notAllowedText && this.disabled) {
this.toastError(this.notAllowedText)
}
},
},
const store = useStore()
const { toastError } = useAppToast()
defineProps({
initialValue: { type: Boolean, default: false },
attrName: { type: String },
enabledText: { type: String },
disabledText: { type: String },
disabled: { type: Boolean, default: false },
notAllowedText: { type: String, default: undefined },
})
const value = ref(props.initialValue)
const isDisabled = computed(() => {
return props.disabled
})
const { mutate: updateUserData } = useMutation(updateUserInfos)
// const onChange = async () => {
// if (isDisabled.value) return
// const variables = []
// variables[props.attrName] = value.value
// try {
// await updateUserData({ variables })
// store.commit(props.attrName, value.value)
// emit('valueChanged', value.value)
// toastSuccess(value.value ? props.enabledText : props.disabledText)
// } catch (error) {
// value.value = props.initialValue
// toastError(error.message)
// }
// }
const onClick = () => {
if (props.notAllowedText && props.disabled) {
toastError(props.notAllowedText)
}
}
const emit = defineEmits(['valueChanged'])
</script>

View File

@ -1,7 +1,7 @@
<template>
<div class="card bg-white gradido-border-radius app-box-shadow p-4 mt--3">
<b-tabs v-model="tabIndex" content-class="mt-3">
<b-tab :title="$t('PersonalDetails')">
<div class="card bg-white gradido-border-radius appBoxShadow p-4 mt--3">
<BTabs v-model="tabIndex" content-class="mt-3">
<BTab :title="$t('PersonalDetails')">
<div class="h2">{{ $t('PersonalDetails') }}</div>
<div class="my-4 text-small">
{{ $t('settings.info') }}
@ -12,45 +12,45 @@
<user-name />
</BCol>
<BCol cols="12" md="6" lg="6">
<b-form-group :label="$t('form.email')" :description="$t('settings.emailInfo')">
<b-form-input v-model="email" readonly></b-form-input>
</b-form-group>
<BFormGroup :label="$t('form.email')" :description="$t('settings.emailInfo')">
<BFormInput v-model="email" readonly></BFormInput>
</BFormGroup>
</BCol>
</BRow>
<hr />
<b-form>
<BForm>
<BRow class="mt-3">
<BCol cols="12" md="6" lg="6">
<label>{{ $t('form.firstname') }}</label>
<b-form-input
<BFormInput
v-model="firstName"
:placeholder="$t('settings.name.enterFirstname')"
data-test="firstname"
trim
></b-form-input>
/>
</BCol>
<BCol cols="12" md="6" lg="6">
<label>{{ $t('form.lastname') }}</label>
<b-form-input
<BFormInput
v-model="lastName"
:placeholder="$t('settings.name.enterLastname')"
data-test="lastname"
trim
></b-form-input>
/>
</BCol>
</BRow>
<div v-if="!isDisabled" class="mt-4 pt-4 text-center">
<b-button
<BButton
type="submit"
variant="primary"
data-test="submit-userdata"
@click.prevent="onSubmit"
>
{{ $t('form.save') }}
</b-button>
</BButton>
</div>
</b-form>
</BForm>
<hr />
<BRow>
<BCol cols="12" md="6" lg="6">{{ $t('language') }}</BCol>
@ -78,9 +78,9 @@
<user-newsletter />
</BCol>
</BRow>
</b-tab>
</BTab>
<div v-if="isCommunityService">
<b-tab class="community-service-tabs" :title="$t('settings.community')">
<BTab class="community-service-tabs" :title="$t('settings.community')">
<div class="h2">{{ $t('settings.allow-community-services') }}</div>
<div v-if="isHumhub" class="mt-3">
<BRow>
@ -147,7 +147,7 @@
{{ $t('settings.GMS.location-format') }}
</BCol>
<BCol cols="12" md="6" lg="6">
<user-g-m-s-location-format />
<!-- <user-g-m-s-location-format /> -->
</BCol>
</BRow>
<BRow class="mb-5">
@ -155,7 +155,7 @@
{{ $t('settings.GMS.location.label') }}
</BCol>
<BCol cols="12" md="6" lg="6">
<user-g-m-s-location />
<!-- <user-g-m-s-location /> -->
</BCol>
</BRow>
</div>
@ -171,123 +171,101 @@
</BRow>
<div class="h4 mt-3 text-muted">{{ $t('GMS.desc') }}</div>
</div>
</b-tab>
</BTab>
</div>
</b-tabs>
</BTabs>
<!-- TODO<BRow>
<BCol cols="12" md="6" lg="6">{{ $t('settings.darkMode') }}</BCol>
<BCol cols="12" md="6" lg="6" class="text-right">
<b-form-checkbox v-model="darkMode" name="dark-mode" switch aligne></b-form-checkbox>
<BForm-checkbox v-model="darkMode" name="dark-mode" switch aligne></BForm-checkbox>
</BCol>
</BRow> -->
</div>
</template>
<script>
import UserNamingFormat from '@/components/UserSettings/UserNamingFormat'
import UserGMSLocationFormat from '@/components/UserSettings/UserGMSLocationFormat'
import UserGMSLocation from '@/components/UserSettings/UserGMSLocation'
import UserName from '@/components/UserSettings/UserName.vue'
import UserPassword from '@/components/UserSettings/UserPassword'
import UserLanguage from '@/components/LanguageSwitch2.vue'
import UserNewsletter from '@/components/UserSettings/UserNewsletter.vue'
import UserSettingsSwitch from '../components/UserSettings/UserSettingsSwitch.vue'
<script setup>
import { useStore } from 'vuex'
import { updateUserInfos } from '@/graphql/mutations'
import CONFIG from '../config'
import { useRoute } from 'vue-router'
import { computed } from 'vue'
import { useMutation } from '@vue/apollo-composable'
import UserName from '@/components/UserSettings/UserName.vue'
import UserLanguage from '@/components/LanguageSwitch2.vue'
import UserPassword from '@/components/UserSettings/UserPassword'
import UserSettingsSwitch from '../components/UserSettings/UserSettingsSwitch.vue'
import UserNamingFormat from '@/components/UserSettings/UserNamingFormat'
// import UserGMSLocationFormat from '@/components/UserSettings/UserGMSLocationFormat'
// import UserGMSLocation from '@/components/UserSettings/UserGMSLocation'
import UserNewsletter from '@/components/UserSettings/UserNewsletter.vue'
import { BTabs, BTab, BRow, BCol, BFormInput, BFormGroup, BForm, BButton } from 'bootstrap-vue-next'
export default {
name: 'Profile',
components: {
UserNamingFormat,
UserGMSLocationFormat,
UserGMSLocation,
UserName,
UserPassword,
UserLanguage,
UserNewsletter,
UserSettingsSwitch,
},
props: {
balance: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
},
const props = defineProps({
balance: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
})
data() {
const { state } = this.$store
const { darkMode, firstName, lastName, email, newsletterState, gmsAllowed, humhubAllowed } =
state
const store = useStore()
const state = store.state
const username = this.$store.state.username || ''
let tabIndex = 0
if (this.$route.params.tabAlias === 'extern') {
tabIndex = 1
}
const route = useRoute()
return {
darkMode,
username,
firstName,
lastName,
email,
newsletterState,
gmsAllowed,
humhubAllowed,
mutation: '',
variables: {},
tabIndex,
}
},
const darkMode = computed(() => state.darkMode)
const firstName = computed(() => state.firstName)
const email = computed(() => state.email)
const newsletterState = computed(() => state.newsletterState)
const gmsAllowed = computed(() => state.gmsAllowed)
const humhubAllowed = computed(() => state.humhubAllowed)
const username = computed(() => state.username || '')
const lastName = computed(() => state.lastName)
computed: {
isDisabled() {
const { firstName, lastName } = this.$store.state
return firstName === this.firstName && lastName === this.lastName
},
isHumhubActivated() {
return this.humhubAllowed === true
},
isCommunityService() {
return this.isGMS || this.isHumhub
},
isGMS() {
return CONFIG.GMS_ACTIVE === 'true'
},
isHumhub() {
return CONFIG.HUMHUB_ACTIVE === 'true'
},
},
// TODO: watch: {
// darkMode(val) {
// this.$store.commit('setDarkMode', this.darkMode)
// this.toastSuccess(
// this.darkMode ? this.$t('settings.modeDark') : this.$t('settings.modeLight'),
// )
// },
// },
methods: {
async onSubmit(key) {
try {
await this.$apollo.mutate({
mutation: updateUserInfos,
variables: {
firstName: this.firstName,
lastName: this.lastName,
},
})
this.$store.commit('firstName', this.firstName)
this.$store.commit('lastName', this.lastName)
this.showUserData = true
this.toastSuccess(this.$t('settings.name.change-success'))
} catch (error) {}
},
gmsStateSwitch(eventData) {
this.gmsAllowed = eventData
},
humhubStateSwitch(eventData) {
this.humhubAllowed = eventData
},
},
let tabIndex = 0
if (route.params.tabAlias === 'extern') {
tabIndex = 1
}
const isDisabled = computed(() => {
return firstName.value === state.firstName && lastName.value === state.lastName
})
const isHumhubActivated = computed(() => {
return humhubAllowed.value === true
})
const isGMS = computed(() => {
return CONFIG.GMS_ACTIVE === 'true'
})
const isHumhub = computed(() => {
return CONFIG.HUMHUB_ACTIVE === 'true'
})
const isCommunityService = computed(() => {
return isGMS.value || isHumhub.value
})
const { mutate: updateUserData } = useMutation(updateUserInfos)
const onSubmit = async (key) => {
try {
await updateUserData({
firstName: firstName.value,
lastName: lastName.value,
}),
store.commit('firstName', firstName.value)
store.commit('lastName', lastName.value)
showUserData.value = true
toastSuccess($t('settings.name.change-success'))
} catch (error) {}
}
// const gmsStateSwitch = (eventData) => {
// gmsAllowed.value = eventData
// }
// const humhubStateSwitch = (eventData) => {
// humhubAllowed.value = eventData
// }
</script>
<style>
.community-service-tabs {