Files
people/src/stores/peopleStore.ts
T
Sebastian b6b3e53095 feat: people import
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
2026-06-22 22:56:31 -04:00

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,
}
})