diff --git a/src/state/guards/index.ts b/src/state/guards/index.ts
index 643cc192..ffd9415e 100644
--- a/src/state/guards/index.ts
+++ b/src/state/guards/index.ts
@@ -4,22 +4,27 @@ export default {
hasNextStep: (context: CR.MachineContext): boolean => {
const { data, position, progress } = context
const steps = data.stages[position.stageId].stepList
- // isn't final step yet
- const hasNext = !!position.stepId && (steps[steps.length - 1] !== position.stepId) || !progress.stages[position.stageId]
+ const stageIncomplete = !progress.stages[position.stageId]
+ const isNotFinalStep = (!!position.stepId && (steps[steps.length - 1] !== position.stepId))
+ const hasNext = stageIncomplete || isNotFinalStep
console.log('GUARD: hasNextStep', hasNext)
return hasNext
},
hasNextStage: (context: CR.MachineContext): boolean => {
- const { data, position } = context
+ const { data, position, progress } = context
const stages = data.levels[position.levelId].stageList
- const hasNext = !!position.stageId && stages[stages.length - 1] !== position.stageId
+ const stageComplete = progress.stages[position.stageId]
+ const isNotFinalStage = !!position.stageId && stages[stages.length - 1] !== position.stageId
+ const hasNext = stageComplete && isNotFinalStage
console.log('GUARD: hasNextStage', hasNext)
return hasNext
},
hasNextLevel: (context: CR.MachineContext): boolean => {
- const { data, position } = context
+ const { data, position, progress } = context
const levels = data.summary.levelList
- const hasNext = !!position.levelId && levels[levels.length - 1] !== position.levelId
+ const levelComplete = progress.levels[position.levelId]
+ const isNotFinalLevel = !!position.levelId && levels[levels.length - 1] !== position.levelId
+ const hasNext = levelComplete && isNotFinalLevel
console.log('GUARD: hasNextLevel', hasNext)
return hasNext
},
diff --git a/src/state/index.ts b/src/state/index.ts
index 3692c088..0e37cf00 100644
--- a/src/state/index.ts
+++ b/src/state/index.ts
@@ -5,6 +5,21 @@ import createMachine from './machine'
// machine interpreter
// https://xstate.js.org/docs/guides/interpretation.html
+// convert state into a readable string
+const stateToString = (state: string | object, str: string = ''): string => {
+ if (typeof state === 'object') {
+ const keys = Object.keys(state)
+ if (keys && keys.length) {
+ const key = keys[0]
+ return stateToString(state[key], str.length ? `${str}.${key}` : key)
+ }
+ return str
+ } else if (typeof state === 'string') {
+ return state
+ }
+ return ''
+}
+
interface Props {
dispatch: CR.EditorDispatch
}
@@ -23,10 +38,8 @@ class StateMachine {
this.service = interpret(machine, this.machineOptions)
// logging
.onTransition(state => {
- // console.log('onTransition', state)
if (state.changed) {
- // console.log('next state')
- // console.log(state.value)
+ console.log(`STATE: ${stateToString(state.value)}`)
dispatch('coderoad.send_state', { state: state.value, data: state.context })
} else {
dispatch('coderoad.send_data', { data: state.context })
diff --git a/src/state/machine.ts b/src/state/machine.ts
index 152d1921..317e3100 100644
--- a/src/state/machine.ts
+++ b/src/state/machine.ts
@@ -47,7 +47,7 @@ export const machine = (dispatch: CR.EditorDispatch) =>
ContinueTutorial: {
onEntry: ['tutorialContinue'],
on: {
- TUTORIAL_START: '#tutorial-load-current',
+ TUTORIAL_START: '#tutorial-load-next',
},
},
},
@@ -57,7 +57,7 @@ export const machine = (dispatch: CR.EditorDispatch) =>
initial: 'Initialize',
onEntry: ['tutorialSetup'],
on: {
- WEBVIEW_INITIALIZED: '#tutorial-load-current'
+ WEBVIEW_INITIALIZED: '#tutorial-load-next'
},
states: {
Initialize: {
@@ -66,28 +66,24 @@ export const machine = (dispatch: CR.EditorDispatch) =>
0: 'Summary',
},
},
- LoadCurrent: {
- id: 'tutorial-load-current',
- // TODO: verify current is not complete
- after: {
- 0: 'Stage',
- },
- },
LoadNext: {
id: 'tutorial-load-next',
after: {
- 0: [
- {
- target: 'Stage',
- cond: 'hasNextStage',
- },
- {
- target: 'Level',
- cond: 'hasNextLevel',
- },
- {
- target: '#end-tutorial',
- },
+ 0: [{
+ target: 'Stage',
+ cond: 'hasNextStep',
+ },
+ {
+ target: 'Stage',
+ cond: 'hasNextStage',
+ },
+ {
+ target: 'Level',
+ cond: 'hasNextLevel',
+ },
+ {
+ target: '#completed-tutorial',
+ },
],
},
},
@@ -157,8 +153,8 @@ export const machine = (dispatch: CR.EditorDispatch) =>
},
},
},
- EndTutorial: {
- id: 'end-tutorial',
+ Completed: {
+ id: 'completed-tutorial',
type: 'final',
},
},
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 23eddb78..652c8d25 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -148,7 +148,6 @@ export interface MachineStateSchema {
states: {
Initialize: {}
Summary: {}
- LoadCurrent: {}
LoadNext: {}
Level: {}
Stage: {
@@ -161,7 +160,7 @@ export interface MachineStateSchema {
StageComplete: {}
}
}
- EndTutorial: {}
+ Completed: {}
}
}
}
diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx
index f6df1ad4..3f4e80fb 100644
--- a/web-app/src/App.tsx
+++ b/web-app/src/App.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as CR from 'typings'
-// import Debugger from './components/Debugger'
+import Debugger from './components/Debugger'
import Routes from './Routes'
import DataContext, { initialData, initialState } from './utils/DataContext'
import { send } from './utils/vscode'
@@ -10,6 +10,8 @@ interface ReceivedEvent {
data: CR.Action
}
+const debug = false
+
const App = () => {
const [state, setState] = React.useState(initialState)
const [data, setData]: [CR.MachineContext, (data: CR.MachineContext) => void] = React.useState(initialData)
@@ -51,7 +53,7 @@ const App = () => {
return (