Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ng <chrng8@gmail.com>2021-06-29 21:46:37 +0300
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2021-07-15 11:16:06 +0300
commit44763576b1180c84b645fcd7017eceaeeeedb094 (patch)
tree7db924e79a46d49ddbc2f2fbb9e672238a6f1ea7 /apps/settings/src
parentde6e55075bc940ad4b576ba1874ad58960dba11c (diff)
Make emails Vuetiful
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Diffstat (limited to 'apps/settings/src')
-rw-r--r--apps/settings/src/components/PersonalInfo/EmailSection/AddButton.vue78
-rw-r--r--apps/settings/src/components/PersonalInfo/EmailSection/Email.vue323
-rw-r--r--apps/settings/src/components/PersonalInfo/EmailSection/EmailSection.vue117
-rw-r--r--apps/settings/src/components/PersonalInfo/EmailSection/FederationControl.vue160
-rw-r--r--apps/settings/src/components/PersonalInfo/EmailSection/HeaderBar.vue94
-rw-r--r--apps/settings/src/main-personal-info.js38
6 files changed, 810 insertions, 0 deletions
diff --git a/apps/settings/src/components/PersonalInfo/EmailSection/AddButton.vue b/apps/settings/src/components/PersonalInfo/EmailSection/AddButton.vue
new file mode 100644
index 00000000000..83a293ed234
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/EmailSection/AddButton.vue
@@ -0,0 +1,78 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <button
+ :disabled="disabled"
+ @click.stop.prevent="onClick">
+ <span class="icon icon-add" />
+ {{ t('settings', 'Add') }}
+ </button>
+</template>
+
+<script>
+export default {
+ name: 'AddButton',
+
+ props: {
+ disabled: {
+ type: Boolean,
+ default: true,
+ },
+ },
+
+ methods: {
+ onClick(e) {
+ this.$emit('click', e)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+ button {
+ height: 44px;
+ padding: 0 16px;
+ border: none;
+ background-color: transparent;
+
+ &:hover {
+ background-color: rgba(127, 127, 127, .15);
+ }
+
+ &:enabled {
+ opacity: 0.4 !important;
+
+ .icon {
+ opacity: 0.8 !important;
+ }
+ }
+
+ &:enabled:hover {
+ background-color: rgba(127, 127, 127, .25);
+ opacity: 0.8 !important;
+ }
+
+ .icon {
+ margin-right: 8px;
+ }
+ }
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/EmailSection/Email.vue b/apps/settings/src/components/PersonalInfo/EmailSection/Email.vue
new file mode 100644
index 00000000000..7ae01908013
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/EmailSection/Email.vue
@@ -0,0 +1,323 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <div>
+ <div class="email-container">
+ <input
+ ref="email"
+ type="email"
+ :name="inputName"
+ :placeholder="inputPlaceholder"
+ :value="email"
+ autocapitalize="none"
+ autocomplete="on"
+ autocorrect="off"
+ required="true"
+ @input="onEmailChange">
+
+ <div class="email-actions-container">
+ <transition name="fade">
+ <span v-if="showCheckmarkIcon" class="icon-checkmark" />
+ <span v-else-if="showErrorIcon" class="icon-error" />
+ </transition>
+
+ <FederationControl v-if="!primary"
+ class="federation-control"
+ :disabled="federationDisabled"
+ :email="email"
+ :scope.sync="localScope"
+ @update:scope="onScopeChange" />
+
+ <Actions
+ class="actions-email"
+ :aria-label="t('settings', 'Email options')"
+ :disabled="deleteDisabled"
+ :force-menu="true">
+ <ActionButton
+ :aria-label="deleteEmailLabel"
+ :close-after-click="true"
+ icon="icon-delete"
+ @click.stop.prevent="deleteEmail">
+ {{ deleteEmailLabel }}
+ </ActionButton>
+ </Actions>
+ </div>
+ </div>
+
+ <em v-if="primary">
+ {{ t('settings', 'Primary email for password reset and notifications') }}
+ </em>
+ </div>
+</template>
+
+<script>
+import Actions from '@nextcloud/vue/dist/Components/Actions'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
+import { showError } from '@nextcloud/dialogs'
+import debounce from 'debounce'
+
+import FederationControl from './FederationControl'
+import { savePrimaryEmail, saveAdditionalEmail, updateAdditionalEmail, removeAdditionalEmail } from '../../../service/PersonalInfoService'
+
+export default {
+ name: 'Email',
+
+ components: {
+ Actions,
+ ActionButton,
+ FederationControl,
+ },
+
+ props: {
+ email: {
+ type: String,
+ required: true,
+ },
+ scope: {
+ type: String,
+ required: true,
+ },
+ primary: {
+ type: Boolean,
+ default: false,
+ },
+ index: {
+ type: Number,
+ default: 0,
+ },
+ },
+
+ data() {
+ return {
+ initialEmail: this.email,
+ localScope: this.scope,
+ showCheckmarkIcon: false,
+ showErrorIcon: false,
+ }
+ },
+
+ computed: {
+ inputName() {
+ if (this.primary) {
+ return 'email'
+ }
+ return 'additionalEmail[]'
+ },
+
+ inputPlaceholder() {
+ if (this.primary) {
+ return t('settings', 'Your email address')
+ }
+ return t('settings', 'Additional email address {index}', { index: this.index + 1 })
+ },
+
+ federationDisabled() {
+ return !this.initialEmail
+ },
+
+ deleteDisabled() {
+ return !this.containsNoWhitespace(this.email)
+ },
+
+ deleteEmailLabel() {
+ if (this.primary) {
+ return t('settings', 'Remove primary email')
+ }
+ return t('settings', 'Delete email')
+ },
+ },
+
+ methods: {
+ onEmailChange(e) {
+ this.$emit('update:email', e.target.value)
+ // $nextTick() ensures that references to this.email further down the chain give the correct non-outdated value
+ this.$nextTick(() => this.debounceEmailChange())
+ },
+
+ debounceEmailChange: debounce(async function() {
+ if ((this.$refs.email?.checkValidity() && this.containsNoWhitespace(this.email)) || this.email === '') {
+ if (this.primary) {
+ await this.updatePrimaryEmail()
+ } else {
+ if (this.initialEmail && this.email === '') {
+ await this.deleteAdditionalEmail()
+ } else if (this.initialEmail === '') {
+ await this.addAdditionalEmail()
+ } else {
+ await this.updateAdditionalEmail()
+ }
+ }
+ }
+ }, 500),
+
+ async deleteEmail() {
+ if (this.primary) {
+ this.$emit('update:email', '')
+ this.$nextTick(async() => await this.updatePrimaryEmail())
+ } else {
+ await this.deleteAdditionalEmail()
+ }
+ },
+
+ async updatePrimaryEmail() {
+ try {
+ const responseData = await savePrimaryEmail(this.email)
+ this.handleResponse(responseData.ocs?.meta?.status)
+ } catch (e) {
+ if (this.email === '') {
+ this.handleResponse('error', 'Unable to delete primary email address', e)
+ } else {
+ this.handleResponse('error', 'Unable to update primary email address', e)
+ }
+ }
+ },
+
+ async addAdditionalEmail() {
+ try {
+ const responseData = await saveAdditionalEmail(this.email)
+ this.handleResponse(responseData.ocs?.meta?.status)
+ } catch (e) {
+ this.handleResponse('error', 'Unable to add additional email address', e)
+ }
+ },
+
+ async updateAdditionalEmail() {
+ try {
+ const responseData = await updateAdditionalEmail(this.initialEmail, this.email)
+ this.handleResponse(responseData.ocs?.meta?.status)
+ } catch (e) {
+ this.handleResponse('error', 'Unable to update additional email address', e)
+ }
+ },
+
+ async deleteAdditionalEmail() {
+ try {
+ const responseData = await removeAdditionalEmail(this.initialEmail)
+ this.handleDeleteAdditionalEmail(responseData.ocs?.meta?.status)
+ } catch (e) {
+ this.handleResponse('error', 'Unable to delete additional email address', e)
+ }
+ },
+
+ containsNoWhitespace(string) {
+ return /^\S+$/.test(string)
+ },
+
+ handleDeleteAdditionalEmail(status) {
+ if (status === 'ok') {
+ this.$emit('deleteAdditionalEmail')
+ } else {
+ this.handleResponse('error', 'Unable to delete additional email address', {})
+ }
+ },
+
+ handleResponse(status, errorMessage, error) {
+ if (status === 'ok') {
+ // Ensure that local initialEmail state reflects server state
+ this.initialEmail = this.email
+ this.showCheckmarkIcon = true
+ setTimeout(() => { this.showCheckmarkIcon = false }, 2000)
+ } else {
+ showError(t('settings', errorMessage))
+ this.logger.error(errorMessage, error)
+ this.showErrorIcon = true
+ setTimeout(() => { this.showErrorIcon = false }, 2000)
+ }
+ },
+
+ onScopeChange(scope) {
+ this.$emit('update:scope', scope)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+ .email-container {
+ display: grid;
+ align-items: center;
+
+ input[type=email] {
+ grid-area: 1 / 1;
+ }
+
+ .email-actions-container {
+ grid-area: 1 / 1;
+ justify-self: flex-end;
+ height: 30px;
+
+ display: flex;
+ gap: 0 2px;
+ margin-right: 5px;
+
+ .actions-email {
+ opacity: 0.4 !important;
+
+ &:hover {
+ opacity: 0.8 !important;
+ }
+
+ &::v-deep button {
+ height: 30px !important;
+ min-height: 30px !important;
+ width: 30px !important;
+ min-width: 30px !important;
+ }
+ }
+
+ .federation-control {
+ &::v-deep button {
+ // TODO remove this hack
+ padding-bottom: 7px;
+ height: 30px !important;
+ min-height: 30px !important;
+ width: 30px !important;
+ min-width: 30px !important;
+ }
+ }
+
+ .icon-checkmark,
+ .icon-error {
+ height: 30px !important;
+ min-height: 30px !important;
+ width: 30px !important;
+ min-width: 30px !important;
+ top: 0;
+ right: 0;
+ float: none;
+ }
+ }
+ }
+
+ .fade-enter-active {
+ transition: opacity 200ms ease-out;
+ }
+
+ .fade-leave-active {
+ transition: opacity 300ms ease-out;
+ }
+
+ .fade-enter,
+ .fade-leave-to {
+ opacity: 0;
+ }
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/EmailSection/EmailSection.vue b/apps/settings/src/components/PersonalInfo/EmailSection/EmailSection.vue
new file mode 100644
index 00000000000..700036872b4
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/EmailSection/EmailSection.vue
@@ -0,0 +1,117 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <form
+ ref="form"
+ class="section"
+ @submit.stop.prevent="() => {}">
+ <HeaderBar
+ :can-edit-emails="isDisplayNameChangeSupported"
+ :is-valid-form="isValidForm"
+ :scope.sync="primaryEmail.scope"
+ @addAdditionalEmail="onAddAdditionalEmail" />
+
+ <template v-if="isDisplayNameChangeSupported">
+ <Email
+ :primary="true"
+ :scope.sync="primaryEmail.scope"
+ :email.sync="primaryEmail.value"
+ @update:email="updateFormValidity" />
+ <Email v-for="(additionalEmail, index) in additionalEmails"
+ :key="index"
+ :index="index"
+ :scope.sync="additionalEmail.scope"
+ :email.sync="additionalEmail.value"
+ @update:email="updateFormValidity"
+ @deleteAdditionalEmail="onDeleteAdditionalEmail(index)" />
+ </template>
+
+ <span v-else>
+ {{ primaryEmail.value || t('settings', 'No email address set') }}
+ </span>
+ </form>
+</template>
+
+<script>
+import { loadState } from '@nextcloud/initial-state'
+import '@nextcloud/dialogs/styles/toast.scss'
+
+import HeaderBar from './HeaderBar'
+import Email from './Email'
+import { DEFAULT_ADDITIONAL_EMAIL_SCOPE } from '../../../constants/AccountPropertyConstants'
+
+const { additionalEmails, primaryEmail } = loadState('settings', 'emails', {})
+const accountParams = loadState('settings', 'accountParameters', {})
+
+export default {
+ name: 'EmailSection',
+
+ components: {
+ HeaderBar,
+ Email,
+ },
+
+ data() {
+ return {
+ accountParams,
+ additionalEmails,
+ primaryEmail,
+ isValidForm: true,
+ }
+ },
+
+ computed: {
+ isDisplayNameChangeSupported() {
+ return this.accountParams.displayNameChangeSupported
+ },
+ },
+
+ mounted() {
+ this.$nextTick(() => this.updateFormValidity())
+ },
+
+ methods: {
+ onAddAdditionalEmail() {
+ if (this.$refs.form?.checkValidity()) {
+ this.additionalEmails.push({ value: '', scope: DEFAULT_ADDITIONAL_EMAIL_SCOPE })
+ this.$nextTick(() => this.updateFormValidity())
+ }
+ },
+
+ onDeleteAdditionalEmail(index) {
+ this.$delete(this.additionalEmails, index)
+ },
+
+ updateFormValidity() {
+ this.isValidForm = this.$refs.form?.checkValidity()
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+ form::v-deep button {
+ &:disabled {
+ cursor: default;
+ }
+ }
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/EmailSection/FederationControl.vue b/apps/settings/src/components/PersonalInfo/EmailSection/FederationControl.vue
new file mode 100644
index 00000000000..87496a81160
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/EmailSection/FederationControl.vue
@@ -0,0 +1,160 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <Actions
+ class="actions-federation"
+ :aria-label="t('settings', 'Change privacy level of email')"
+ :default-icon="scopeIcon"
+ :disabled="disabled">
+ <ActionButton v-for="federationScope in federationScopes"
+ :key="federationScope.name"
+ class="forced-action"
+ :class="{ 'forced-active': scope === federationScope.name }"
+ :aria-label="federationScope.tooltip"
+ :close-after-click="true"
+ :icon="federationScope.iconClass"
+ :title="federationScope.displayName"
+ @click.stop.prevent="changeScope(federationScope.name)">
+ {{ federationScope.tooltip }}
+ </ActionButton>
+ </Actions>
+</template>
+
+<script>
+import Actions from '@nextcloud/vue/dist/Components/Actions'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
+import { showError } from '@nextcloud/dialogs'
+
+import { SCOPE_ENUM, SCOPE_PROPERTY_ENUM } from '../../../constants/AccountPropertyConstants'
+import { savePrimaryEmailScope, saveAdditionalEmailScope } from '../../../service/PersonalInfoService'
+
+// TODO hardcoded for email, should abstract this for other sections
+const excludedScopes = [SCOPE_ENUM.PRIVATE]
+
+export default {
+ name: 'FederationControl',
+
+ components: {
+ Actions,
+ ActionButton,
+ },
+
+ props: {
+ primary: {
+ type: Boolean,
+ default: false,
+ },
+ email: {
+ type: String,
+ default: '',
+ },
+ scope: {
+ type: String,
+ required: true,
+ },
+ disabled: {
+ type: Boolean,
+ default: false,
+ },
+ },
+
+ data() {
+ return {
+ initialScope: this.scope,
+ federationScopes: Object.values(SCOPE_PROPERTY_ENUM).filter(({ name }) => !excludedScopes.includes(name)),
+ }
+ },
+
+ computed: {
+ scopeIcon() {
+ return SCOPE_PROPERTY_ENUM[this.scope].iconClass
+ },
+ },
+
+ methods: {
+ async changeScope(scope) {
+ this.$emit('update:scope', scope)
+
+ this.$nextTick(async() => {
+ if (this.primary) {
+ await this.updatePrimaryEmailScope()
+ } else {
+ await this.updateAdditionalEmailScope()
+ }
+ })
+ },
+
+ async updatePrimaryEmailScope() {
+ try {
+ const responseData = await savePrimaryEmailScope(this.scope)
+ this.handleResponse(responseData.ocs?.meta?.status)
+ } catch (e) {
+ this.handleResponse('error', 'Unable to update federation scope of the primary email', e)
+ }
+ },
+
+ async updateAdditionalEmailScope() {
+ try {
+ const responseData = await saveAdditionalEmailScope(this.email, this.scope)
+ this.handleResponse(responseData.ocs?.meta?.status)
+ } catch (e) {
+ this.handleResponse('error', 'Unable to update federation scope of additional email', e)
+ }
+ },
+
+ handleResponse(status, errorMessage, error) {
+ if (status === 'ok') {
+ this.initialScope = this.scope
+ } else {
+ this.$emit('update:scope', this.initialScope)
+ showError(t('settings', errorMessage))
+ this.logger.error(errorMessage, error)
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+ .actions-federation {
+ opacity: 0.4 !important;
+
+ &:hover {
+ opacity: 0.8 !important;
+ }
+ }
+
+ .forced-active {
+ background-color: var(--color-primary-light) !important;
+ box-shadow: inset 2px 0 var(--color-primary) !important;
+ }
+
+ .forced-action {
+ &::v-deep p {
+ width: 150px !important;
+ padding: 8px 0 !important;
+ color: var(--color-main-text) !important;
+ font-size: 12.8px !important;
+ line-height: 1.5em !important;
+ }
+ }
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/EmailSection/HeaderBar.vue b/apps/settings/src/components/PersonalInfo/EmailSection/HeaderBar.vue
new file mode 100644
index 00000000000..7d2b1ab76b6
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/EmailSection/HeaderBar.vue
@@ -0,0 +1,94 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <h3>
+ <label for="email">
+ {{ t('settings', 'Email') }}
+ </label>
+
+ <FederationControl
+ class="federation-control"
+ :primary="true"
+ :scope.sync="localScope"
+ @update:scope="onScopeChange" />
+
+ <AddButton v-if="canEditEmails"
+ class="add-button"
+ :disabled="!isValidForm"
+ @click.stop.prevent="addAdditionalEmail" />
+ </h3>
+</template>
+
+<script>
+import FederationControl from './FederationControl'
+import AddButton from './AddButton'
+
+export default {
+ name: 'HeaderBar',
+
+ components: {
+ FederationControl,
+ AddButton,
+ },
+
+ props: {
+ canEditEmails: {
+ type: Boolean,
+ default: true,
+ },
+ isValidForm: {
+ type: Boolean,
+ default: true,
+ },
+ scope: {
+ type: String,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ localScope: this.scope,
+ }
+ },
+
+ methods: {
+ addAdditionalEmail() {
+ this.$emit('addAdditionalEmail')
+ },
+
+ onScopeChange(scope) {
+ this.$emit('update:scope', scope)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+ .federation-control {
+ margin: -12px 0 0 8px;
+ }
+
+ .add-button {
+ margin: -12px 0 0 auto !important;
+ }
+</style>
diff --git a/apps/settings/src/main-personal-info.js b/apps/settings/src/main-personal-info.js
new file mode 100644
index 00000000000..8edbd29669f
--- /dev/null
+++ b/apps/settings/src/main-personal-info.js
@@ -0,0 +1,38 @@
+/**
+ * @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import Vue from 'vue'
+
+import logger from './logger'
+
+import EmailSection from './components/PersonalInfo/EmailSection/EmailSection'
+
+// eslint-disable-next-line camelcase
+__webpack_nonce__ = btoa(OC.requestToken)
+
+Vue.prototype.t = t
+Vue.prototype.logger = logger
+
+const View = Vue.extend(EmailSection)
+export default new View({
+ el: '#vue-emailsection',
+})