import { mainTaskComponentID , Task , TaskComponentState , } from "../entities/task" ; import { EntityType } from "../entity" ; import { EventID , EventType , TaskIngestEvent , TaskRepetitionEvent , TaskRescheduleEvent , TaskUpdateDeletedEvent , TaskUpdateProvenanceEvent , } from "../event" ; import { createSpacedRepetitionScheduler } from "../schedulers/spacedRepetitionScheduler" ; export function taskIngestEventReducer ( oldSnapshot , event ) { if ( oldSnapshot ) { return { ... oldSnapshot , provenance : event . provenance ?? oldSnapshot . provenance , spec : oldSnapshot . spec , metadata : { ... oldSnapshot . metadata , ... event . metadata } , } ; } else { const specComponents = "components" in event . spec . content ? event . spec . content . components : null ; const componentIDs = specComponents ? Object . keys ( specComponents ) : [ mainTaskComponentID ] ; return { id : event . entityID , type : EntityType . Task , createdAtTimestampMillis : event . timestampMillis , spec : event . spec , provenance : event . provenance , metadata : event . metadata ?? { } , isDeleted : false , componentStates : Object . fromEntries ( componentIDs . map ( ( id ) => [ id , { createdAtTimestampMillis : event . timestampMillis , lastRepetitionTimestampMillis : null , dueTimestampMillis : event . timestampMillis , intervalMillis : 0 , } , ] ) ) , } ; } } const scheduler = createSpacedRepetitionScheduler ( ) ; export function taskRepetitionEventReducer ( oldSnapshot , event ) { assertTaskExists ( oldSnapshot , event . type ) ; return modifyTaskComponent ( oldSnapshot , event . componentID , event . id , ( oldState ) => ( { createdAtTimestampMillis : oldState . createdAtTimestampMillis , lastRepetitionTimestampMillis : event . timestampMillis , ... scheduler . computeNextDueIntervalMillisForRepetition ( oldState , event . timestampMillis , event . outcome ) , } ) ) ; } export function taskRescheduleEventReducer ( oldSnapshot , event ) { assertTaskExists ( oldSnapshot , event . type ) ; return modifyTaskComponent ( oldSnapshot , event . componentID , event . id , ( oldState ) => ( { ... oldState , dueTimestampMillis : event . newDueTimestampMillis , } ) ) ; } export function taskUpdateDeletedEventReducer ( oldSnapshot , event ) { assertTaskExists ( oldSnapshot , event . type ) ; return { ... oldSnapshot , isDeleted : event . isDeleted } ; } export function taskUpdateProvenanceEventReducer ( oldSnapshot , event ) { assertTaskExists ( oldSnapshot , event . type ) ; return { ... oldSnapshot , provenance : event . provenance } ; } function modifyTaskComponent ( oldSnapshot , componentID , eventID , transformer ) { const componentState = oldSnapshot . componentStates [ componentID ] ; if ( ! componentState ) { console . error ( `Repetition on unknown component ${ componentID } in event ${ eventID } on ${ oldSnapshot . id }` ) ; return oldSnapshot ; } return { ... oldSnapshot , componentStates : { ... oldSnapshot . componentStates , [ componentID ] : transformer ( oldSnapshot . componentStates [ componentID ] ) , } , } ; } function assertTaskExists ( snapshot , eventType ) { if ( snapshot === null ) { throw new Error ( `Can't apply an event of type ${ eventType } to a task without a prior snapshot` ) ; } }