import { debug } from 'loglevel' import { AttributeData, ElementData, ElementFormData } from '../interfaces' import { CheckList, CheckPoint, Element, ELEMENT_NAME, Record as RecordModel, RecordStatus, } from '../models' import { MainStore } from './mainStore' export class ChecklistStore { main: MainStore constructor(main: MainStore) { this.main = main } async startChecklist( checklist: string, element: string, ): Promise<{ record: RecordModel checklist: CheckList }> { const organization = this.main.userStore.organization.id const recordTypeP = this.resolveRecordType(organization) // load checklist with children const checklistP = this.main.elements.getRaw( checklist, CheckList.TYPE, undefined, { scope: ['children', 'element'], childrenAtt: Object.values(CheckPoint.ATTRIBUTES), }, ) const [recordType, checklistFull] = await Promise.all([ recordTypeP, checklistP, ]) if (!checklistFull || !checklistFull.element) { throw new Error('Checklist not found') } const schema = await this.main.elementStore.getElementSchema(recordType) if (!schema) { throw new Error( `Failed to load type schema for "${recordType}". Check network connectivity and try again.`, ) } debug( `Loaded checklist ${ (checklistFull.element.element_name as AttributeData)?.value }`, ) const checkPoints = checklistFull.children ?? [] const checklistInstance = this.main.elementStore.instantiateElementWithChildren(checklistFull) debug('Checkpoints count: ', checkPoints.length) const mainRecord = this.createChecklistRecord( recordType, checklistFull.element, element, organization, ) const subRecords = checkPoints.map((cp) => this.createCheckpointRecord( recordType, cp.element, element, organization, ), ) mainRecord.children = subRecords return { record: mainRecord as unknown as RecordModel, checklist: checklistInstance as CheckList, } } async resolveRecordType(organization: string): Promise { const organizationSpecificRecordType = `${organization}-Record` // load privileges for organization specific types console.time('resolve record type') const privilegesP = this.main.elements.getPrivileges( organization, organizationSpecificRecordType, ) const privilegesOrg = await privilegesP // Resolve privileges (with fallback to shared privileges if not found) let recordType: string | undefined if ( !privilegesOrg || !privilegesOrg.data?.privileges.type?.includes('create') ) { console.time('get shared privileges') const sharedPrivileges = await this.main.elements.getPrivileges( RecordModel.TYPE, organization, ) console.timeEnd('get shared privileges') if ( !sharedPrivileges || !sharedPrivileges?.data?.privileges.type?.includes('create') ) { throw new Error('You do not have permission to start a checklist') } else { recordType = RecordModel.TYPE } } else { recordType = organizationSpecificRecordType } console.timeEnd('resolve record type') return recordType } createChecklistRecord( recordType: string, checklist: ElementData, element: string, organization: string, ) { const cl = Element.dehydrateDataAndUnwrapValues(checklist) const description = cl[CheckList.ATTRIBUTES.DESCRIPTION] as string const data: ElementFormData = { [ELEMENT_NAME]: cl.element_name as string, [RecordModel.ATTRIBUTES.STATUS]: RecordStatus.OPEN, [RecordModel.ATTRIBUTES.CHECKLIST_ATE]: checklist.hash, [RecordModel.ATTRIBUTES.ELEMENTS]: element, } const newElement = this.main.elementStore.instantiateLocalElement( recordType, organization, ) if (description) { data[RecordModel.ATTRIBUTES.RECORD_DESCRIPTION] = description } newElement.setAttributes(data) return newElement } createCheckpointRecord( recordType: string, checkpoint: ElementData, element: string, organization: string, ) { const cp = Element.dehydrateDataAndUnwrapValues(checkpoint) // order is string on CheckPoint but number on Record so we need to parse it const order = Number(cp[CheckPoint.ATTRIBUTES.ORDER] as string) || 0 const data: ElementFormData = { element_name: cp.element_name as string, [RecordModel.ATTRIBUTES.STATUS]: RecordStatus.OPEN, [RecordModel.ATTRIBUTES.CHECKLIST_ATE]: checkpoint.hash, [RecordModel.ATTRIBUTES.ELEMENTS]: element, [RecordModel.ATTRIBUTES.ORDER]: order, } const newElement = this.main.elementStore.instantiateLocalElement( recordType, organization, ) newElement.setAttributes(data) return newElement } }