Last active
April 15, 2021 14:54
-
-
Save elsangedy/406c699dac828d3bbd6cbd0fac87d4a1 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // TAP BACKEND | |
| const appMachine = Machine( | |
| { | |
| id: 'tap', | |
| context: {}, | |
| initial: 'bootstrap', | |
| on: { | |
| RESTART: 'bootstrap', | |
| }, | |
| states: { | |
| bootstrap: { | |
| entry: ['reset', 'bootstrapStarted'], | |
| onDone: [ | |
| { | |
| target: 'maintenance', | |
| cond: 'isOnMaintenance', | |
| }, | |
| { | |
| target: 'operation', | |
| cond: 'isConfigured', | |
| }, | |
| { | |
| target: 'bootstrap', | |
| }, | |
| ], | |
| initial: 'authentication', | |
| on: { | |
| ERROR: '.unavailable', | |
| }, | |
| states: { | |
| authentication: { | |
| entry: ['authenticationStarted'], | |
| on: { | |
| AUTHENTICATE: [ | |
| { | |
| target: 'configuration', | |
| actions: ['saveAuth'], | |
| cond: 'isSetuped', | |
| }, | |
| { | |
| target: 'setup', | |
| actions: ['saveAuth'], | |
| }, | |
| ], | |
| }, | |
| after: { | |
| AUTHENTICATION_TIMEOUT: 'unavailable', | |
| }, | |
| }, | |
| setup: { | |
| entry: ['setupStarted'], | |
| on: { | |
| AUTHENTICATE: [ | |
| { | |
| target: 'configuration', | |
| actions: ['saveAuth'], | |
| cond: 'isSetuped', | |
| }, | |
| { | |
| target: 'setup', | |
| actions: ['saveAuth'], | |
| }, | |
| ], | |
| }, | |
| }, | |
| configuration: { | |
| invoke: { | |
| src: 'getConfiguration', | |
| onDone: { | |
| target: 'done', | |
| actions: ['saveConfiguration'], | |
| }, | |
| onError: 'unavailable', | |
| }, | |
| }, | |
| unavailable: { | |
| entry: ['unavailableStarted'], | |
| after: { | |
| UNAVAILABLE_RETRY_TIMEOUT: 'done', | |
| }, | |
| }, | |
| done: { | |
| type: 'final' | |
| } | |
| }, | |
| }, | |
| maintenance: { | |
| entry: ['startMaintenance', 'maintenanceStarted'], | |
| exit: ['finishMaintenance'], | |
| on: { | |
| FINISH_MAINTENANCE: 'bootstrap', | |
| }, | |
| initial: 'idle', | |
| states: { | |
| idle: { | |
| on: { | |
| START_CALIBRATION: { | |
| actions: ['saveMaintenanceConsumption'], | |
| target: 'calibration', | |
| }, | |
| START_DEPLETION: { | |
| actions: ['saveMaintenanceConsumption'], | |
| target: 'depletion', | |
| }, | |
| }, | |
| }, | |
| calibration: { | |
| entry: ['calibrationStarted'], | |
| exit: ['calibrationFinished'], | |
| onDone: 'idle', | |
| initial: 'flow', | |
| states: { | |
| flow: { | |
| on: { | |
| FLOW: { | |
| actions: ['incrementPulses', 'flowmeterPulsed'], | |
| target: 'flow', | |
| }, | |
| }, | |
| after: { | |
| CALIBRATION_TIMEOUT: 'calibrate', | |
| }, | |
| }, | |
| calibrate: { | |
| invoke: { | |
| src: 'calibrate', | |
| onDone: 'done', | |
| onError: 'done', | |
| }, | |
| }, | |
| done: { | |
| type: 'final', | |
| }, | |
| }, | |
| }, | |
| depletion: { | |
| entry: ['depletionStarted'], | |
| exit: ['depletionFinished'], | |
| on: { | |
| FINISH_DEPLETION: 'idle', | |
| FLOW: { | |
| actions: ['incrementPulses', 'flowmeterPulsed'], | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| operation: { | |
| entry: ['operationStarted'], | |
| on: { | |
| START_MAINTENANCE: 'maintenance', | |
| }, | |
| initial: 'idle', | |
| states: { | |
| idle: { | |
| on: { | |
| ORDER: { | |
| target: 'startingConsumption', | |
| actions: ['saveCustomer'], | |
| }, | |
| IDENTIFIED: 'identifying', | |
| }, | |
| }, | |
| identifying: { | |
| invoke: { | |
| src: 'getCustomerByTag', | |
| onDone: { | |
| target: 'startingConsumption', | |
| actions: ['saveCustomer'], | |
| }, | |
| onError: { | |
| target: 'idle', | |
| actions: ['identificationFailure'], | |
| }, | |
| }, | |
| }, | |
| startingConsumption: { | |
| invoke: { | |
| src: 'startConsumption', | |
| onDone: { | |
| target: 'consumption', | |
| actions: ['saveConsumption'], | |
| }, | |
| onError: { | |
| target: 'idle', | |
| actions: ['startingConsumptionFailure'], | |
| }, | |
| }, | |
| }, | |
| consumption: { | |
| entry: ['consumptionStarted'], | |
| initial: 'flow', | |
| onDone: 'idle', | |
| states: { | |
| flow: { | |
| on: { | |
| FLOW: [ | |
| { | |
| actions: ['incrementPulses', 'flowmeterPulsed'], | |
| target: 'flow', | |
| cond: 'hasCredit', | |
| }, | |
| { | |
| actions: [ | |
| 'incrementPulses', | |
| 'flowmeterPulsed', | |
| 'consumptionFinishedByNoCredit', | |
| ], | |
| target: 'done', | |
| }, | |
| ], | |
| }, | |
| after: { | |
| CONSUMPTION_TIMEOUT: [ | |
| { | |
| target: 'done', | |
| cond: (context) => context.consumption?.pulses === 0, | |
| actions: ['consumptionFinishedByTimeout'], | |
| }, | |
| { | |
| target: 'done', | |
| actions: ['consumptionFinishedByDebounce'], | |
| }, | |
| ], | |
| }, | |
| }, | |
| done: { | |
| type: 'final', | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| delays: { | |
| CALIBRATION_TIMEOUT: 20000, | |
| AUTHENTICATION_TIMEOUT: 30000, | |
| UNAVAILABLE_RETRY_TIMEOUT: 10000, | |
| CONSUMPTION_TIMEOUT: (context) => { | |
| if (context?.consumption?.pulses === 0) { | |
| return context?.configuration?.consumptionTimeoutTime; | |
| } | |
| return context?.configuration?.consumptionDebounceTime; | |
| }, | |
| }, | |
| guards: { | |
| isSetuped: (_, event) => { | |
| return !!event.data?.active; | |
| }, | |
| isConfigured: (context) => { | |
| return !!context.configuration; | |
| }, | |
| isOnMaintenance: (_, event) => { | |
| return !!event.data?.inMaintenance; | |
| }, | |
| hasCredit: (context) => { | |
| return context.consumption?.pulses < context.consumption?.maxPulses; | |
| }, | |
| }, | |
| actions: { | |
| reset: assign({ | |
| auth: null, | |
| customer: null, | |
| consumption: null, | |
| configuration: null, | |
| }), | |
| saveAuth: assign({ | |
| auth: (_, event) => { | |
| return event.data; | |
| }, | |
| }), | |
| saveConfiguration: assign({ | |
| configuration: (_, event) => { | |
| return event.data; | |
| }, | |
| }), | |
| startMaintenance: assign({ | |
| configuration: (context) => { | |
| return { | |
| ...context.configuration, | |
| inMaintenance: true, | |
| }; | |
| }, | |
| }), | |
| finishMaintenance: assign({ | |
| configuration: (context) => { | |
| return { | |
| ...context.configuration, | |
| inMaintenance: false, | |
| }; | |
| }, | |
| }), | |
| saveCustomer: assign( | |
| { | |
| customer: (_, event) => { | |
| return event.data; | |
| }, | |
| }, | |
| ), | |
| saveMaintenanceConsumption: assign({ | |
| consumption: () => { | |
| return { | |
| id: null, | |
| pulses: 0, | |
| maxPulses: Infinity, | |
| }; | |
| }, | |
| }), | |
| saveConsumption: assign({ | |
| consumption: (context, event) => { | |
| const factor = context.configuration.factorPulseToMl; | |
| const balance = context.customer.balance; | |
| const price = context.configuration.productPrice; | |
| const maxAmount = Math.floor(balance / price); | |
| const maxPulses = Math.floor(maxAmount / factor); | |
| return { | |
| ...event.data, | |
| pulses: 0, | |
| maxPulses, | |
| }; | |
| }, | |
| }), | |
| incrementPulses: assign({ | |
| consumption: (context) => { | |
| return { | |
| ...context.consumption, | |
| pulses: context.consumption.pulses + 1, | |
| }; | |
| }, | |
| }), | |
| }, | |
| }, | |
| ); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment