mirror of https://github.com/nextcloud/contacts
327 lines
8.1 KiB
Vue
327 lines
8.1 KiB
Vue
<!--
|
|
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
|
|
-
|
|
- @author John Molakvoæ <skjnldsv@protonmail.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 id="content" class="app-contacts">
|
|
|
|
<!-- new-contact-button + navigation + settings -->
|
|
<app-navigation :menu="menu">
|
|
<!-- settings -->
|
|
<settings-section v-if="!loading" slot="settings-content" />
|
|
</app-navigation>
|
|
|
|
<!-- main content -->
|
|
<div id="app-content">
|
|
<div id="app-content-wrapper">
|
|
<!-- loading -->
|
|
<import-screen v-if="importState.stage !== 'default'" />
|
|
<template v-else>
|
|
<!-- contacts list -->
|
|
<content-list :list="contactsList" :contacts="contacts" :loading="loading"
|
|
:search-query="searchQuery" />
|
|
<!-- main contacts details -->
|
|
<contact-details :loading="loading" :uid="selectedContact" />
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { AppNavigation } from 'nextcloud-vue'
|
|
|
|
import SettingsSection from '../components/SettingsSection'
|
|
import ContentList from '../components/ContentList'
|
|
import ContactDetails from '../components/ContactDetails'
|
|
import ImportScreen from '../components/ImportScreen'
|
|
|
|
import Contact from '../models/contact'
|
|
import rfcProps from '../models/rfcProps.js'
|
|
|
|
import client from '../services/cdav.js'
|
|
|
|
export default {
|
|
components: {
|
|
AppNavigation,
|
|
SettingsSection,
|
|
ContentList,
|
|
ContactDetails,
|
|
ImportScreen
|
|
},
|
|
|
|
// passed by the router
|
|
props: {
|
|
selectedGroup: {
|
|
type: String,
|
|
default: undefined,
|
|
required: true
|
|
},
|
|
selectedContact: {
|
|
type: String,
|
|
default: undefined
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
loading: true,
|
|
searchQuery: ''
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
// store getters
|
|
addressbooks() {
|
|
return this.$store.getters.getAddressbooks
|
|
},
|
|
sortedContacts() {
|
|
return this.$store.getters.getSortedContacts
|
|
},
|
|
contacts() {
|
|
return this.$store.getters.getContacts
|
|
},
|
|
groups() {
|
|
return this.$store.getters.getGroups
|
|
},
|
|
orderKey() {
|
|
return this.$store.getters.getOrderKey
|
|
},
|
|
importState() {
|
|
return this.$store.getters.getImportState
|
|
},
|
|
// first enabled addressbook of the list
|
|
defaultAddressbook() {
|
|
return this.addressbooks.find(addressbook => !addressbook.readOnly)
|
|
},
|
|
|
|
/**
|
|
* Contacts list based on the selected group.
|
|
* Those filters are pretty fast, so let's only
|
|
* intersect the groups contacts and the full
|
|
* sorted contacts List.
|
|
*
|
|
* @returns {Array}
|
|
*/
|
|
contactsList() {
|
|
if (this.selectedGroup === t('contacts', 'All contacts')) {
|
|
return this.sortedContacts
|
|
}
|
|
let group = this.groups.filter(group => group.name === this.selectedGroup)[0]
|
|
if (group) {
|
|
return this.sortedContacts.filter(contact => group.contacts.indexOf(contact.key) >= 0)
|
|
}
|
|
return []
|
|
},
|
|
|
|
// generate groups menu from groups store
|
|
groupsMenu() {
|
|
return this.groups.map(group => {
|
|
return {
|
|
id: group.name.replace(' ', '_'),
|
|
key: group.name.replace(' ', '_'),
|
|
router: {
|
|
name: 'group',
|
|
params: { selectedGroup: group.name }
|
|
},
|
|
text: group.name,
|
|
utils: {
|
|
counter: group.contacts.length
|
|
}
|
|
}
|
|
}).sort(function(a, b) {
|
|
return parseInt(b.utils.counter) - parseInt(a.utils.counter)
|
|
})
|
|
},
|
|
|
|
// building the main menu
|
|
menu() {
|
|
if (this.loading) {
|
|
return {
|
|
id: 'groups-list',
|
|
loading: true
|
|
}
|
|
}
|
|
return {
|
|
id: 'groups-list',
|
|
new: {
|
|
id: 'new-contact-button',
|
|
text: t('contacts', 'New contact'),
|
|
icon: 'icon-add',
|
|
action: this.newContact
|
|
},
|
|
items: this.allGroup.concat(this.groupsMenu)
|
|
}
|
|
},
|
|
|
|
// default group for every contacts
|
|
allGroup() {
|
|
return [{
|
|
id: 'everyone',
|
|
key: 'everyone',
|
|
icon: 'icon-contacts-dark',
|
|
router: {
|
|
name: 'group',
|
|
params: { selectedGroup: t('contacts', 'All contacts') }
|
|
},
|
|
text: t('contacts', 'All contacts'),
|
|
utils: {
|
|
counter: this.sortedContacts.length
|
|
}
|
|
}]
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
// watch url change and group select
|
|
selectedGroup: function() {
|
|
this.selectFirstContactIfNone()
|
|
},
|
|
// watch url change and contact select
|
|
selectedContact: function() {
|
|
this.selectFirstContactIfNone()
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
/**
|
|
* Register search
|
|
*/
|
|
this.search = new OCA.Search(this.search, this.resetSearch)
|
|
},
|
|
|
|
beforeMount() {
|
|
// get addressbooks then get contacts
|
|
client.connect({ enableCardDAV: true }).then(() => {
|
|
console.debug('Connected to dav!', client)
|
|
this.$store.dispatch('getAddressbooks')
|
|
.then((addressbooks) => {
|
|
|
|
// No addressbooks? Create a new one!
|
|
if (addressbooks.length === 0) {
|
|
this.$store.dispatch('appendAddressbook', { displayName: t('contacts', 'Contacts') })
|
|
.then(() => {
|
|
this.fetchContacts()
|
|
})
|
|
// else, let's get those contacts!
|
|
} else {
|
|
this.fetchContacts()
|
|
}
|
|
})
|
|
// check local storage for orderKey
|
|
if (localStorage.getItem('orderKey')) {
|
|
// run setOrder mutation with local storage key
|
|
this.$store.commit('setOrder', localStorage.getItem('orderKey'))
|
|
}
|
|
})
|
|
},
|
|
|
|
methods: {
|
|
newContact() {
|
|
let contact = new Contact('BEGIN:VCARD\nVERSION:4.0\nEND:VCARD', this.defaultAddressbook)
|
|
contact.fullName = 'New contact'
|
|
// itterate over all properties (filter is not usable on objects and we need the key of the property)
|
|
for (let name in rfcProps.properties) {
|
|
if (rfcProps.properties[name].default) {
|
|
let defaultData = rfcProps.properties[name].defaultValue
|
|
// add default field
|
|
let property = contact.vCard.addPropertyWithValue(name, defaultData.value)
|
|
// add default type
|
|
if (defaultData.type) {
|
|
property.setParameter('type', defaultData.type)
|
|
|
|
}
|
|
}
|
|
}
|
|
if (this.selectedGroup !== t('contacts', 'All contacts')) {
|
|
contact.vCard.addPropertyWithValue('categories', this.selectedGroup)
|
|
}
|
|
this.$store.dispatch('addContact', contact)
|
|
.then(() => {
|
|
this.$router.push({
|
|
name: 'contact',
|
|
params: {
|
|
selectedGroup: this.selectedGroup,
|
|
selectedContact: contact.key
|
|
}
|
|
})
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Dispatch sorting update request to the store
|
|
*
|
|
* @param {string} orderKey the object key to order by
|
|
*/
|
|
updateSorting(orderKey = 'displayName') {
|
|
this.$store.commit('setOrder', orderKey)
|
|
this.$store.commit('sortContacts')
|
|
},
|
|
|
|
/**
|
|
* Fetch the contacts of each addressbooks
|
|
*/
|
|
fetchContacts() {
|
|
// wait for all addressbooks to have fetch their contacts
|
|
Promise.all(this.addressbooks.map(addressbook => {
|
|
if (addressbook.enabled) {
|
|
return this.$store.dispatch('getContactsFromAddressBook', { addressbook })
|
|
}
|
|
})).then(results => {
|
|
this.loading = false
|
|
this.selectFirstContactIfNone()
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Select the first contact of the list
|
|
* if none are selected already
|
|
*/
|
|
selectFirstContactIfNone() {
|
|
let inList = this.contactsList.findIndex(contact => contact.key === this.selectedContact) > -1
|
|
if (this.selectedContact === undefined || !inList) {
|
|
if (this.selectedContact && !inList) {
|
|
OC.Notification.showTemporary(t('contacts', 'Contact not found'))
|
|
}
|
|
if (Object.keys(this.contactsList).length) {
|
|
this.$router.push({
|
|
name: 'contact',
|
|
params: {
|
|
selectedGroup: this.selectedGroup,
|
|
selectedContact: Object.values(this.contactsList)[0].key
|
|
}
|
|
})
|
|
}
|
|
}
|
|
},
|
|
|
|
/* SEARCH */
|
|
search(query) {
|
|
this.searchQuery = query
|
|
},
|
|
resetSearch() {
|
|
this.search('')
|
|
}
|
|
}
|
|
}
|
|
</script>
|