Skip to content

Commit

Permalink
Vuetify
Browse files Browse the repository at this point in the history
- abstract HeaderBar component

Signed-off-by: Christopher Ng <chrng8@gmail.com>
  • Loading branch information
Pytal committed Aug 17, 2021
1 parent 1d3ddbe commit 40ef0b8
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 39 deletions.
149 changes: 149 additions & 0 deletions apps/settings/src/components/PersonalInfo/LanguageSection/Language.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<!--
- @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 class="language">
<select
id="language"
ref="language"
name="language"
:placeholder="t('settings', 'Language')"
required
@input="onLanguageChange">
<option
:value="language.code">
{{ language.name }}
</option>
<option v-for="commonLanguage in commonLanguages"
:key="commonLanguage.code"
:value="commonLanguage.code">
{{ commonLanguage.name }}
</option>
<optgroup label="––––––––––" />
<option v-for="otherLanguage in otherLanguages"
:key="otherLanguage.code"
:value="otherLanguage.code">
{{ otherLanguage.name }}
</option>
</select>

<a
href="https://www.transifex.com/nextcloud/nextcloud/"
target="_blank"
rel="noreferrer noopener">
<em>{{ t('settings', 'Help translate') }}</em>
</a>
</div>
</template>

<script>
import { showError } from '@nextcloud/dialogs'

import { saveLanguage } from '../../../service/PersonalInfo/LanguageService'

export default {
name: 'Language',

props: {
commonLanguages: {
type: Array,
required: true,
},
otherLanguages: {
type: Array,
required: true,
},
language: {
type: Object,
required: true,
},
},

data() {
return {
initialLanguage: this.language,
}
},

computed: {
allLanguages() {
return Object.freeze(
[...this.commonLanguages, ...this.otherLanguages]
.reduce((acc, { code, name }) => ({ ...acc, [code]: name }), {})
)
},
},

methods: {
async onLanguageChange(e) {
const language = this.constructLanguage(e.target.value)
this.$emit('update:language', language)

if (this.$refs.language?.checkValidity()) {
await this.updateLanguage(language)
}
},

async updateLanguage(language) {
try {
const responseData = await saveLanguage(language.code)
this.handleResponse({
language,
status: responseData.ocs?.meta?.status,
})
this.reloadPage()
} catch (e) {
this.handleResponse({
errorMessage: 'Unable to update language',
error: e,
})
}
},

constructLanguage(languageCode) {
return {
code: languageCode,
name: this.allLanguages[languageCode],
}
},

handleResponse({ language, status, errorMessage, error }) {
if (status === 'ok') {
// Ensure that local state reflects server state
this.initialLanguage = language
} else {
showError(t('settings', errorMessage))
this.logger.error(errorMessage, error)
}
},

reloadPage() {
location.reload()
},
},
}
</script>

<style lang="scss" scoped>
.language {
display: grid;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!--
- @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
:account-property="accountProperty"
label-for="language"
:is-valid-form="isValidForm" />

<template v-if="isEditable">
<Language
:common-languages="commonLanguages"
:other-languages="otherLanguages"
:language.sync="language"
@update:language="onUpdateLanguage" />
</template>

<span v-else>
{{ t('settings', 'No language set') }}
</span>
</form>
</template>

<script>
import { loadState } from '@nextcloud/initial-state'

import Language from './Language'
import HeaderBar from '../shared/HeaderBar'

import { SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'

const { languages: { activeLanguage, commonLanguages, otherLanguages } } = loadState('settings', 'personalInfoParameters', {})

export default {
name: 'LanguageSection',

components: {
Language,
HeaderBar,
},

data() {
return {
accountProperty: SETTING_PROPERTY_READABLE_ENUM.LANGUAGE,
isValidForm: true,
commonLanguages,
otherLanguages,
language: activeLanguage,
}
},

computed: {
isEditable() {
return Boolean(this.language)
},
},

mounted() {
this.$nextTick(() => this.updateFormValidity())
},

methods: {
onUpdateLanguage() {
this.$nextTick(() => this.updateFormValidity())
},

updateFormValidity() {
this.isValidForm = this.$refs.form?.checkValidity()
},
},
}
</script>

<style lang="scss" scoped>
form::v-deep button {
&:disabled {
cursor: default;
}
}
</style>
46 changes: 35 additions & 11 deletions apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@
-->

<template>
<h3>
<h3
:class="{ 'setting-property': isSettingProperty }">
<label :for="labelFor">
{{ t('settings', accountProperty) }}
</label>

<FederationControl
class="federation-control"
:account-property="accountProperty"
:handle-scope-change="handleScopeChange"
:scope.sync="localScope"
@update:scope="onScopeChange" />
<template v-if="scope && handleScopeChange">
<FederationControl
class="federation-control"
:account-property="accountProperty"
:handle-scope-change="handleScopeChange"
:scope.sync="localScope"
@update:scope="onScopeChange" />
</template>

<template v-if="isEditable && isMultiValueSupported">
<AddButton
Expand All @@ -45,7 +48,7 @@
import AddButton from './AddButton'
import FederationControl from './FederationControl'

import { ACCOUNT_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'
import { ACCOUNT_PROPERTY_READABLE_ENUM, SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'

export default {
name: 'HeaderBar',
Expand All @@ -59,11 +62,11 @@ export default {
accountProperty: {
type: String,
required: true,
validator: (value) => Object.values(ACCOUNT_PROPERTY_READABLE_ENUM).includes(value),
validator: (value) => Object.values(ACCOUNT_PROPERTY_READABLE_ENUM).includes(value) || Object.values(SETTING_PROPERTY_READABLE_ENUM).includes(value),
},
handleScopeChange: {
type: Function,
required: true,
default: null,
},
isEditable: {
type: Boolean,
Expand All @@ -83,7 +86,7 @@ export default {
},
scope: {
type: String,
required: true,
default: null,
},
},

Expand All @@ -93,6 +96,12 @@ export default {
}
},

computed: {
isSettingProperty() {
return Object.values(SETTING_PROPERTY_READABLE_ENUM).includes(this.accountProperty)
},
},

methods: {
onAddAdditional() {
this.$emit('add-additional')
Expand All @@ -106,6 +115,21 @@ export default {
</script>

<style lang="scss" scoped>
h3.setting-property {
min-height: 37px;
position: relative;
display: inline-flex;
flex-wrap: nowrap;
justify-content: flex-start;
width: 100%;

label {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}

.federation-control {
margin: -12px 0 0 8px;
}
Expand Down
4 changes: 3 additions & 1 deletion apps/settings/src/main-personal-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import logger from './logger'

import DisplayNameSection from './components/PersonalInfo/DisplayNameSection/DisplayNameSection'
import EmailSection from './components/PersonalInfo/EmailSection/EmailSection'
import LanguageSection from './components/PersonalInfo/LanguageSection/LanguageSection'

// eslint-disable-next-line camelcase
__webpack_nonce__ = btoa(getRequestToken())

Vue.mixin({
Expand All @@ -44,6 +44,8 @@ Vue.mixin({

const DisplayNameView = Vue.extend(DisplayNameSection)
const EmailView = Vue.extend(EmailSection)
const LanguageView = Vue.extend(LanguageSection)

new DisplayNameView().$mount('#vue-displaynamesection')
new EmailView().$mount('#vue-emailsection')
new LanguageView().$mount('#vue-languagesection')
Loading

0 comments on commit 40ef0b8

Please sign in to comment.