xref: /openbmc/webui-vue/src/views/ProfileSettings/ProfileSettings.vue (revision de23ea23d88451a2fa2774ec72053772603c23ae)
1<template>
2  <b-container fluid="xl">
3    <page-title />
4
5    <b-row>
6      <b-col md="8" lg="8" xl="6">
7        <page-section
8          :section-title="$t('pageProfileSettings.profileInfoTitle')"
9        >
10          <dl>
11            <dt>{{ $t('pageProfileSettings.username') }}</dt>
12            <dd>
13              {{ username }}
14            </dd>
15          </dl>
16        </page-section>
17      </b-col>
18    </b-row>
19
20    <b-form @submit.prevent="submitForm">
21      <b-row>
22        <b-col sm="8" md="6" xl="3">
23          <page-section
24            :section-title="$t('pageProfileSettings.changePassword')"
25          >
26            <b-form-group
27              id="input-group-0"
28              :label="$t('pageProfileSettings.currentPassword')"
29              label-for="input-0"
30            >
31              <input-password-toggle>
32                <b-form-input
33                  id="old-password"
34                  v-model="form.currentPassword"
35                  type="password"
36                  data-test-id="profileSettings-input-ocurrentPassword"
37                  class="form-control-with-button"
38                />
39              </input-password-toggle>
40            </b-form-group>
41            <b-form-group
42              id="input-group-1"
43              :label="$t('pageProfileSettings.newPassword')"
44              label-for="input-1"
45            >
46              <b-form-text id="password-help-block">
47                {{
48                  $t('pageUserManagement.modal.passwordMustBeBetween', {
49                    min: passwordRequirements.minLength,
50                    max: passwordRequirements.maxLength,
51                  })
52                }}
53              </b-form-text>
54              <input-password-toggle>
55                <b-form-input
56                  id="password"
57                  v-model="form.newPassword"
58                  type="password"
59                  aria-describedby="password-help-block"
60                  :state="getValidationState(v$.form.newPassword)"
61                  data-test-id="profileSettings-input-newPassword"
62                  class="form-control-with-button"
63                  @input="v$.form.newPassword.$touch()"
64                />
65                <b-form-invalid-feedback role="alert">
66                  <template
67                    v-if="
68                      !v$.form.newPassword.minLength ||
69                      !v$.form.newPassword.maxLength
70                    "
71                  >
72                    {{
73                      $t('pageProfileSettings.newPassLabelTextInfo', {
74                        min: passwordRequirements.minLength,
75                        max: passwordRequirements.maxLength,
76                      })
77                    }}
78                  </template>
79                </b-form-invalid-feedback>
80              </input-password-toggle>
81            </b-form-group>
82            <b-form-group
83              id="input-group-2"
84              :label="$t('pageProfileSettings.confirmPassword')"
85              label-for="input-2"
86            >
87              <input-password-toggle>
88                <b-form-input
89                  id="password-confirmation"
90                  v-model="form.confirmPassword"
91                  type="password"
92                  :state="getValidationState(v$.form.confirmPassword)"
93                  data-test-id="profileSettings-input-confirmPassword"
94                  class="form-control-with-button"
95                  @input="v$.form.confirmPassword.$touch()"
96                />
97                <b-form-invalid-feedback role="alert">
98                  <template v-if="!v$.form.confirmPassword.sameAsPassword">
99                    {{ $t('pageProfileSettings.passwordsDoNotMatch') }}
100                  </template>
101                </b-form-invalid-feedback>
102              </input-password-toggle>
103            </b-form-group>
104          </page-section>
105        </b-col>
106      </b-row>
107      <page-section :section-title="$t('pageProfileSettings.timezoneDisplay')">
108        <p>{{ $t('pageProfileSettings.timezoneDisplayDesc') }}</p>
109        <b-row>
110          <b-col md="9" lg="8" xl="9">
111            <b-form-group :label="$t('pageProfileSettings.timezone')">
112              <b-form-radio
113                v-model="form.isUtcDisplay"
114                :value="true"
115                data-test-id="profileSettings-radio-defaultUTC"
116              >
117                {{ $t('pageProfileSettings.defaultUTC') }}
118              </b-form-radio>
119              <b-form-radio
120                v-model="form.isUtcDisplay"
121                :value="false"
122                data-test-id="profileSettings-radio-browserOffset"
123              >
124                {{
125                  $t('pageProfileSettings.browserOffset', {
126                    timezone,
127                  })
128                }}
129              </b-form-radio>
130            </b-form-group>
131          </b-col>
132        </b-row>
133      </page-section>
134      <b-button
135        variant="primary"
136        type="submit"
137        data-test-id="profileSettings-button-saveSettings"
138      >
139        {{ $t('global.action.saveSettings') }}
140      </b-button>
141    </b-form>
142  </b-container>
143</template>
144
145<script>
146import BVToastMixin from '@/components/Mixins/BVToastMixin';
147import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
148import { maxLength, minLength, sameAs } from '@vuelidate/validators';
149import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
150import LocalTimezoneLabelMixin from '@/components/Mixins/LocalTimezoneLabelMixin';
151import PageTitle from '@/components/Global/PageTitle';
152import PageSection from '@/components/Global/PageSection';
153import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
154import { useVuelidate } from '@vuelidate/core';
155import { useI18n } from 'vue-i18n';
156import i18n from '@/i18n';
157
158export default {
159  name: 'ProfileSettings',
160  components: { InputPasswordToggle, PageSection, PageTitle },
161  mixins: [
162    BVToastMixin,
163    LocalTimezoneLabelMixin,
164    LoadingBarMixin,
165    VuelidateMixin,
166  ],
167  setup() {
168    return {
169      v$: useVuelidate(),
170    };
171  },
172  data() {
173    return {
174      $t: useI18n().t,
175      form: {
176        newPassword: '',
177        confirmPassword: '',
178        currentPassword: '',
179        isUtcDisplay: this.$store.getters['global/isUtcDisplay'],
180      },
181    };
182  },
183  computed: {
184    username() {
185      return this.$store.getters['global/username'];
186    },
187    passwordRequirements() {
188      return this.$store.getters['userManagement/accountPasswordRequirements'];
189    },
190    timezone() {
191      return this.localOffset();
192    },
193  },
194  created() {
195    this.startLoader();
196    this.$store
197      .dispatch('userManagement/getAccountSettings')
198      .finally(() => this.endLoader());
199  },
200  validations() {
201    return {
202      form: {
203        newPassword: {
204          minLength: minLength(this.passwordRequirements.minLength),
205          maxLength: maxLength(this.passwordRequirements.maxLength),
206        },
207        confirmPassword: {
208          sameAsPassword: sameAs('newPassword'),
209        },
210      },
211    };
212  },
213  methods: {
214    saveNewPasswordInputData() {
215      this.v$.form.confirmPassword.$touch();
216      this.v$.form.newPassword.$touch();
217      if (this.v$.$invalid) return;
218      let userData = {
219        originalUsername: this.username,
220        password: this.form.newPassword,
221      };
222
223      this.$store
224        .dispatch('userManagement/updateUser', userData)
225        .then((message) => {
226          (this.form.newPassword = ''),
227            (this.form.confirmPassword = ''),
228            (this.form.currentPassword = '');
229          this.v$.$reset();
230          this.successToast(message);
231          this.$store.dispatch('authentication/logout');
232        })
233        .catch(({ message }) => this.errorToast(message));
234    },
235    saveTimeZonePrefrenceData() {
236      localStorage.setItem('storedUtcDisplay', this.form.isUtcDisplay);
237      this.$store.commit('global/setUtcTime', this.form.isUtcDisplay);
238      this.successToast(
239        i18n.global.t('pageProfileSettings.toast.successUpdatingTimeZone'),
240      );
241    },
242    submitForm() {
243      if (
244        this.form.confirmPassword &&
245        this.form.newPassword &&
246        this.form.currentPassword
247      ) {
248        this.confirmAuthenticate();
249      }
250      if (
251        this.$store.getters['global/isUtcDisplay'] != this.form.isUtcDisplay
252      ) {
253        this.saveTimeZonePrefrenceData();
254      }
255    },
256    confirmAuthenticate() {
257      this.v$.form.newPassword.$touch();
258      if (this.v$.$invalid) return;
259
260      const username = this.username;
261      const password = this.form.currentPassword;
262
263      this.$store
264        .dispatch('authentication/login', { username, password })
265        .then(() => {
266          this.saveNewPasswordInputData();
267        })
268        .catch(() => {
269          this.v$.$reset();
270          this.errorToast(
271            i18n.global.t('pageProfileSettings.toast.wrongCredentials'),
272          );
273        });
274    },
275  },
276};
277</script>
278