b6b3e53095
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
277 lines
7.4 KiB
TypeScript
277 lines
7.4 KiB
TypeScript
import { computed, ref, shallowRef } from 'vue'
|
|
import { defineStore } from 'pinia'
|
|
import { CollectionObject } from '@PeopleManager/models/collection'
|
|
import { EntityObject } from '@PeopleManager/models/entity'
|
|
import { IndividualObject } from '@PeopleManager/models/individual'
|
|
import { OrganizationObject } from '@PeopleManager/models/organization'
|
|
import { GroupObject } from '@PeopleManager/models/group'
|
|
import type { ServiceObject } from '@PeopleManager/models/service'
|
|
import { useCollectionsStore } from '@PeopleManager/stores/collectionsStore'
|
|
import { useEntitiesStore } from '@PeopleManager/stores/entitiesStore'
|
|
import { useServicesStore } from '@PeopleManager/stores/servicesStore'
|
|
import { useImportStore } from '@PeopleManager/stores/importStore'
|
|
|
|
export const usePeopleStore = defineStore('peopleStore', () => {
|
|
const servicesStore = useServicesStore()
|
|
const collectionsStore = useCollectionsStore()
|
|
const entitiesStore = useEntitiesStore()
|
|
const importStore = useImportStore()
|
|
|
|
// UI state
|
|
const sidebarVisible = ref(true)
|
|
const loading = ref(false)
|
|
|
|
// Selection state
|
|
const selectedCollection = shallowRef<CollectionObject | null>(null)
|
|
const selectedEntity = shallowRef<EntityObject | null>(null)
|
|
|
|
// Entity editor state
|
|
const entityEditorMode = ref<'edit' | 'view'>('view')
|
|
|
|
// Collection editor state
|
|
const showCollectionEditor = ref(false)
|
|
const editingCollection = shallowRef<CollectionObject | null>(null)
|
|
const collectionEditorMode = ref<'create' | 'edit'>('create')
|
|
|
|
// Import state
|
|
const showImportDialog = ref(false)
|
|
|
|
// Derived state
|
|
const collections = computed(() => collectionsStore.collections)
|
|
const entities = computed(() => entitiesStore.entities)
|
|
|
|
// --- Collection actions ---
|
|
|
|
function selectCollection(collection: CollectionObject) {
|
|
selectedCollection.value = collection
|
|
selectedEntity.value = null
|
|
}
|
|
|
|
function openEditCollection(collection: CollectionObject) {
|
|
editingCollection.value = collection
|
|
collectionEditorMode.value = 'edit'
|
|
showCollectionEditor.value = true
|
|
}
|
|
|
|
function openCreateCollection() {
|
|
editingCollection.value = new CollectionObject()
|
|
collectionEditorMode.value = 'create'
|
|
showCollectionEditor.value = true
|
|
}
|
|
|
|
async function saveCollection(collection: CollectionObject, service: ServiceObject) {
|
|
if (collectionEditorMode.value === 'create') {
|
|
const created = await collectionsStore.create(
|
|
service.provider,
|
|
service.identifier ?? '',
|
|
collection.properties,
|
|
)
|
|
selectedCollection.value = created
|
|
} else {
|
|
await collectionsStore.update(
|
|
collection.identifier,
|
|
collection.properties,
|
|
)
|
|
}
|
|
|
|
showCollectionEditor.value = false
|
|
}
|
|
|
|
async function deleteCollection(collection: CollectionObject) {
|
|
await collectionsStore.delete(collection.identifier)
|
|
|
|
if (selectedCollection.value?.identifier === collection.identifier) {
|
|
selectedCollection.value = null
|
|
selectedEntity.value = null
|
|
}
|
|
|
|
showCollectionEditor.value = false
|
|
}
|
|
|
|
// --- Entity actions ---
|
|
|
|
function createEntity(type: string) {
|
|
const entity = new EntityObject()
|
|
|
|
if (type === 'organization') {
|
|
entity.properties = new OrganizationObject()
|
|
} else if (type === 'group') {
|
|
entity.properties = new GroupObject()
|
|
} else {
|
|
entity.properties = new IndividualObject()
|
|
}
|
|
|
|
selectedEntity.value = entity
|
|
entityEditorMode.value = 'edit'
|
|
}
|
|
|
|
function selectEntity(entity: EntityObject) {
|
|
selectedEntity.value = entity
|
|
entityEditorMode.value = 'view'
|
|
}
|
|
|
|
function startEditingEntity() {
|
|
entityEditorMode.value = 'edit'
|
|
}
|
|
|
|
function cancelEditingEntity() {
|
|
entityEditorMode.value = 'view'
|
|
}
|
|
|
|
function closeEntityEditor() {
|
|
selectedEntity.value = null
|
|
entityEditorMode.value = 'view'
|
|
}
|
|
|
|
async function saveEntity(entity: EntityObject, collection?: CollectionObject | null) {
|
|
const targetCollection = collection instanceof CollectionObject
|
|
? collection
|
|
: selectedCollection.value
|
|
|
|
if (!targetCollection) {
|
|
throw new Error('[People] - No collection selected, cannot save entity')
|
|
}
|
|
|
|
if (!entity.identifier) {
|
|
// Create
|
|
entity.properties.created = new Date()
|
|
selectedEntity.value = await entitiesStore.create(
|
|
targetCollection.identifier,
|
|
entity.properties,
|
|
)
|
|
} else {
|
|
// Update
|
|
entity.properties.modified = new Date()
|
|
selectedEntity.value = await entitiesStore.update(
|
|
entity.identifier,
|
|
entity.properties,
|
|
)
|
|
}
|
|
|
|
selectedCollection.value = targetCollection
|
|
entityEditorMode.value = 'view'
|
|
}
|
|
|
|
async function deleteEntity(entity: EntityObject, collection?: CollectionObject | null) {
|
|
const targetCollection = collection instanceof CollectionObject
|
|
? collection
|
|
: selectedCollection.value
|
|
|
|
if (!targetCollection) {
|
|
throw new Error('[People] - No collection selected, cannot delete entity')
|
|
}
|
|
|
|
await entitiesStore.delete([entity.identifier])
|
|
|
|
closeEntityEditor()
|
|
}
|
|
|
|
// --- Import actions ---
|
|
|
|
/**
|
|
* Queue selected VCF files and open the import dialog.
|
|
* Defaults each file's target to the currently selected collection.
|
|
*/
|
|
async function openImport(files: File[]) {
|
|
importStore.removeAllFiles()
|
|
importStore.reset()
|
|
|
|
for (const file of files) {
|
|
const contents = await file.text()
|
|
const id = importStore.addFile({
|
|
name: file.name,
|
|
contents,
|
|
size: file.size,
|
|
type: file.type,
|
|
})
|
|
if (selectedCollection.value) {
|
|
importStore.setCollectionForFile(id, selectedCollection.value.identifier)
|
|
}
|
|
}
|
|
|
|
importStore.stage = 'selecting'
|
|
showImportDialog.value = true
|
|
}
|
|
|
|
/**
|
|
* Close the import dialog. When refresh is requested, reload the entity lists for
|
|
* every collection that received contacts, then clear the import queue.
|
|
*/
|
|
async function closeImport(refresh: boolean = false) {
|
|
showImportDialog.value = false
|
|
|
|
if (refresh) {
|
|
const targets = new Set<CollectionObject['identifier']>()
|
|
for (const id of importStore.order) {
|
|
const target = importStore.sessions[id]?.targetIdentifier
|
|
if (target) targets.add(target)
|
|
}
|
|
for (const target of targets) {
|
|
await entitiesStore.list([target])
|
|
}
|
|
}
|
|
|
|
importStore.removeAllFiles()
|
|
importStore.reset()
|
|
}
|
|
|
|
// --- Lifecycle ---
|
|
|
|
async function initialize() {
|
|
loading.value = true
|
|
try {
|
|
await servicesStore.list()
|
|
await collectionsStore.list()
|
|
|
|
if (
|
|
selectedCollection.value
|
|
&& !collections.value.find(c => c.identifier === selectedCollection.value?.identifier)
|
|
) {
|
|
selectedCollection.value = null
|
|
}
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
// State
|
|
sidebarVisible,
|
|
loading,
|
|
selectedCollection,
|
|
selectedEntity,
|
|
entityEditorMode,
|
|
showCollectionEditor,
|
|
editingCollection,
|
|
collectionEditorMode,
|
|
showImportDialog,
|
|
|
|
// Derived
|
|
collections,
|
|
entities,
|
|
|
|
// Collection actions
|
|
selectCollection,
|
|
openEditCollection,
|
|
openCreateCollection,
|
|
saveCollection,
|
|
deleteCollection,
|
|
|
|
// Entity actions
|
|
createEntity,
|
|
selectEntity,
|
|
startEditingEntity,
|
|
cancelEditingEntity,
|
|
closeEntityEditor,
|
|
saveEntity,
|
|
deleteEntity,
|
|
|
|
// Import actions
|
|
openImport,
|
|
closeImport,
|
|
|
|
// Lifecycle
|
|
initialize,
|
|
}
|
|
})
|