Add ChangePassword component

Add non-functional Change password page and router definition.
The page has a form and some frontend validations but backend
functionality and api requests are not tied in yet. Page can be
viewed by manually navigating to /change-password.

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: If5e6c6a5120b86fc457d8cab4c82333c33ef745f
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index 2a41804..76d9aaf 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -35,6 +35,7 @@
       "invalidValue": "Invalid value",
       "lengthMustBeBetween": "Length must be between %{min} – %{max} characters",
       "mustBeAtLeast": "Must be at least %{value}",
+      "passwordsDoNotMatch": "Passwords do not match",
       "required": "Required",
       "search": "Search",
       "selectAnOption": "Select an option",
@@ -93,6 +94,7 @@
     "sslCertificates": "@:appPageTitle.sslCertificates"
   },
   "appPageTitle": {
+    "changePassword": "Change password",
     "dateTimeSettings": "Date and time settings",
     "eventLogs": "Event logs",
     "firmware": "Firmware",
@@ -113,6 +115,14 @@
     "sslCertificates": "SSL Certificates",
     "unauthorized": "Unauthorized"
   },
+  "pageChangePassword": {
+    "changePassword": "Change password",
+    "changePasswordAlertMessage": "The password is expired and must be changed.",
+    "confirmNewPassword": "Confirm new password",
+    "goBack": "Go back",
+    "newPassword": "New password",
+    "username": "Username"
+  },
   "pageDateTimeSettings": {
     "alert": {
       "message": "To change how date and time are displayed (either UTC or browser offset) throughout the application, visit ",
diff --git a/src/router/index.js b/src/router/index.js
index 3d8c646..8fa42c8 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -158,6 +158,14 @@
         meta: {
           title: 'appPageTitle.login'
         }
+      },
+      {
+        path: '/change-password',
+        name: 'change-password',
+        component: () => import('@/views/ChangePassword'),
+        meta: {
+          title: 'appPageTitle.changePassword'
+        }
       }
     ]
   },
diff --git a/src/views/ChangePassword/ChangePassword.vue b/src/views/ChangePassword/ChangePassword.vue
new file mode 100644
index 0000000..0b1b689
--- /dev/null
+++ b/src/views/ChangePassword/ChangePassword.vue
@@ -0,0 +1,115 @@
+<template>
+  <div class="change-password-container mx-auto ml-md-5 mb-3">
+    <alert variant="danger" class="mb-4">
+      <p>{{ $t('pageChangePassword.changePasswordAlertMessage') }}</p>
+    </alert>
+    <dl>
+      <dt>{{ $t('pageChangePassword.username') }}</dt>
+      <dd>{{ username }}</dd>
+    </dl>
+    <b-form novalidate @submit.prevent="changePassword">
+      <b-form-group
+        label-for="password"
+        :label="$t('pageChangePassword.newPassword')"
+      >
+        <input-password-toggle>
+          <b-form-input
+            id="password"
+            v-model="form.password"
+            autofocus="autofocus"
+            type="password"
+            :state="getValidationState($v.form.password)"
+            @blur="$v.form.password.$touch()"
+          >
+          </b-form-input>
+          <b-form-invalid-feedback role="alert">
+            <template v-if="!$v.form.password.required">
+              {{ $t('global.form.fieldRequired') }}
+            </template>
+          </b-form-invalid-feedback>
+        </input-password-toggle>
+      </b-form-group>
+      <b-form-group
+        label-for="password-confirm"
+        :label="$t('pageChangePassword.confirmNewPassword')"
+      >
+        <input-password-toggle>
+          <b-form-input
+            id="password-confirm"
+            v-model="form.passwordConfirm"
+            type="password"
+            :state="getValidationState($v.form.passwordConfirm)"
+            @blur="$v.form.passwordConfirm.$touch()"
+          >
+          </b-form-input>
+          <b-form-invalid-feedback role="alert">
+            <template v-if="!$v.form.passwordConfirm.required">
+              {{ $t('global.form.fieldRequired') }}
+            </template>
+            <template v-else-if="!$v.form.passwordConfirm.sameAsPassword">
+              {{ $t('global.form.passwordsDoNotMatch') }}
+            </template>
+          </b-form-invalid-feedback>
+        </input-password-toggle>
+      </b-form-group>
+      <div class="text-right">
+        <b-button type="button" variant="link" to="login" @click="goBack">
+          {{ $t('pageChangePassword.goBack') }}
+        </b-button>
+        <b-button type="submit" variant="primary">
+          {{ $t('pageChangePassword.changePassword') }}
+        </b-button>
+      </div>
+    </b-form>
+  </div>
+</template>
+
+<script>
+import { required, sameAs } from 'vuelidate/lib/validators';
+import Alert from '@/components/Global/Alert';
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
+import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
+
+export default {
+  name: 'ChangePassword',
+  components: { Alert, InputPasswordToggle },
+  mixins: [VuelidateMixin],
+  data() {
+    return {
+      form: {
+        password: null,
+        passwordConfirm: null
+      },
+      username: this.$store.getters['global/username']
+    };
+  },
+  validations() {
+    return {
+      form: {
+        password: { required },
+        passwordConfirm: {
+          required,
+          sameAsPassword: sameAs('password')
+        }
+      }
+    };
+  },
+  methods: {
+    goBack() {
+      // Remove temporary session created if navigating back
+      // to the Login page
+      this.$store.commit('authentication/logout');
+    },
+    changePassword() {
+      // Should make PATCH request with new password
+      // then reroute to Overview page
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.change-password-container {
+  max-width: 360px;
+}
+</style>
diff --git a/src/views/ChangePassword/index.js b/src/views/ChangePassword/index.js
new file mode 100644
index 0000000..9de0af4
--- /dev/null
+++ b/src/views/ChangePassword/index.js
@@ -0,0 +1,2 @@
+import ChangePassword from './ChangePassword.vue';
+export default ChangePassword;