Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1dd6646

Browse files
authored
Merge pull requestcoderoad#301 from coderoad/fix/continue
Fix/continue
2 parentse577682 +edb6b13 commit1dd6646

File tree

9 files changed

+117
-92
lines changed

9 files changed

+117
-92
lines changed

‎CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ Resulting in a folder structure like the following:
9494

9595
## [0.4.0]
9696

97-
- Navigate through text content from previous levels.
97+
-Want to look back at a previous lesson's content?Navigate through text content from previous levels by clicking the "Learn" dropdown.
9898

9999
![traverse content](./docs/images/traverse-content.png)
100100

101-
- Fixes progress navigation bug when no steps in a level
101+
- Continue an incomplete tutorial started in the same workspace. Choose the "continue" path from the start screen. Progress is stored in local storage in the workspace.
102+
103+
![continue tutorial](./docs/images/continue-tutorial.png)

‎docs/images/continue-tutorial.png

62.3 KB
Loading

‎src/channel/index.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,22 @@ class Channel implements Channel {
7575
// continue from tutorial from local storage
7676
consttutorial:TT.Tutorial|null=this.context.tutorial.get()
7777

78-
// new tutorial
79-
this.send({type:'START_NEW_TUTORIAL',payload:{ env}})
80-
return
81-
82-
// disable continue until fixed
83-
84-
// // set tutorial
85-
// const { position, progress } = await this.context.setTutorial(this.workspaceState, tutorial)
78+
// no stored tutorial, must start new tutorial
79+
if(!tutorial||!tutorial.id){
80+
this.send({type:'START_NEW_TUTORIAL',payload:{ env}})
81+
return
82+
}
8683

87-
// if (progress.complete) {
88-
// // tutorial is already complete
89-
// this.send({ type: 'TUTORIAL_ALREADY_COMPLETE', payload: { env }})
90-
// return
91-
// }
92-
// // communicate to client the tutorial & stepProgress state
93-
// this.send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, progress, position }})
84+
// load continued tutorial position & progress
85+
const{ position, progress}=awaitthis.context.setTutorial(this.workspaceState,tutorial)
9486

95-
// return
87+
if(progress.complete){
88+
// tutorial is already complete
89+
this.send({type:'TUTORIAL_ALREADY_COMPLETE',payload:{ env}})
90+
return
91+
}
92+
// communicate to client the tutorial & stepProgress state
93+
this.send({type:'LOAD_STORED_TUTORIAL',payload:{ env, tutorial, progress, position}})
9694
}catch(e){
9795
consterror={
9896
type:'UnknownError',

‎web-app/src/components/Router/index.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ declare let acquireVsCodeApi: any
1717

1818
consteditor=acquireVsCodeApi()
1919
consteditorSend=(action:T.Action)=>{
20-
logger(`CLIENTTO EXT: "${action.type}"`)
20+
logger(`TO EXT: "${action.type}"`)
2121
returneditor.postMessage(action)
2222
}
2323

2424
// router finds first state match of <Route path='' />
2525
constuseRouter=():Output=>{
2626
const[state,send]=useMachine<T.MachineContext,any>(createMachine({ editorSend}))
2727

28+
constsendWithLog=(action:T.Action):void=>{
29+
logger(`SEND:${action.type}`,action)
30+
send(action)
31+
}
32+
2833
logger(`STATE:${JSON.stringify(state.value)}`)
2934

3035
// event bus listener
@@ -38,8 +43,7 @@ const useRouter = (): Output => {
3843
if(action.source){
3944
return
4045
}
41-
logger(`CLIENT RECEIVED: "${action.type}"`)
42-
send(action)
46+
sendWithLog(action)
4347
}
4448
window.addEventListener(listener,handler)
4549
return()=>{
@@ -74,7 +78,7 @@ const useRouter = (): Output => {
7478

7579
return{
7680
context:state.context,
77-
send,
81+
send:sendWithLog,
7882
Router,
7983
Route,
8084
}

‎web-app/src/containers/Start/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ interface ContainerProps {
8686
constStartPageContainer=({ context, send}:ContainerProps)=>{
8787
consttutorial=context.tutorial||undefined
8888
return(
89-
<StartPageonContinue={()=>send('CONTINUE_TUTORIAL')}onNew={()=>send('NEW_TUTORIAL')}tutorial={tutorial}/>
89+
<StartPage
90+
onContinue={()=>send({type:'CONTINUE_TUTORIAL'})}
91+
onNew={()=>send({type:'NEW_TUTORIAL'})}
92+
tutorial={tutorial}
93+
/>
9094
)
9195
}
9296

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import*asReactfrom'react'
2+
import*asTfrom'typings'
3+
import*asTTfrom'typings/tutorial'
4+
import{Menu}from'@alifd/next'
5+
importIconfrom'../../components/Icon'
6+
7+
interfaceProps{
8+
tutorial:TT.Tutorial
9+
position:T.Position
10+
progress:T.Progress
11+
setTitle:(title:string)=>void
12+
setContent:(content:string)=>void
13+
}
14+
15+
constContentMenu=({ tutorial, position, progress, setTitle, setContent}:Props)=>{
16+
constsetMenuContent=(levelId:string)=>{
17+
constselectedLevel:TT.Level|undefined=tutorial.levels.find((l:TT.Level)=>l.id===levelId)
18+
if(selectedLevel){
19+
setTitle(selectedLevel.title)
20+
setContent(selectedLevel.content)
21+
}
22+
}
23+
return(
24+
<Menu>
25+
{tutorial.levels.map((level:TT.Level)=>{
26+
constisCurrent=level.id===position.levelId
27+
constisComplete=progress.levels[level.id]
28+
leticon
29+
letdisabled=false
30+
31+
if(isComplete){
32+
// completed icon
33+
icon=<Icontype="minus"size="xs"/>
34+
}elseif(isCurrent){
35+
// current icon`
36+
icon=<Icontype="minus"size="xs"/>
37+
}else{
38+
// upcoming
39+
disabled=true
40+
icon=<Icontype="lock"size="xs"/>
41+
}
42+
return(
43+
<Menu.Itemkey={level.id}disabled={disabled}onSelect={()=>setMenuContent(level.id)}>
44+
{icon}&nbsp;&nbsp;&nbsp;{level.title}
45+
</Menu.Item>
46+
)
47+
})}
48+
</Menu>
49+
)
50+
}
51+
52+
exportdefaultContentMenu

‎web-app/src/containers/Tutorial/index.tsx

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import*asReactfrom'react'
22
import*asTfrom'typings'
33
import*asTTfrom'typings/tutorial'
4-
import{Menu}from'@alifd/next'
54
import*asselectorsfrom'../../services/selectors'
6-
importIconfrom'../../components/Icon'
5+
importContentMenufrom'./ContentMenu'
76
importLevelfrom'./components/Level'
8-
importloggerfrom'../../services/logger'
97

108
interfacePageProps{
119
context:T.MachineContext
@@ -23,9 +21,9 @@ const TutorialPage = (props: PageProps) => {
2321

2422
constonContinue=():void=>{
2523
props.send({
26-
type:'LEVEL_NEXT',
24+
type:'NEXT_LEVEL',
2725
payload:{
28-
LevelId:position.levelId,
26+
levelId:position.levelId,
2927
},
3028
})
3129
}
@@ -45,48 +43,19 @@ const TutorialPage = (props: PageProps) => {
4543
return{ ...step, status}
4644
})
4745

48-
constsetMenuContent=(levelId:string)=>{
49-
constselectedLevel:TT.Level|undefined=tutorial.levels.find((l:TT.Level)=>l.id===levelId)
50-
if(selectedLevel){
51-
setTitle(selectedLevel.title)
52-
setContent(selectedLevel.content)
53-
}
54-
}
55-
56-
constmenu=(
57-
<Menu>
58-
{tutorial.levels.map((level:TT.Level)=>{
59-
constisCurrent=level.id===position.levelId
60-
logger('progress',progress)
61-
constisComplete=progress.levels[level.id]
62-
leticon
63-
letdisabled=false
64-
65-
if(isComplete){
66-
// completed icon
67-
icon=<Icontype="minus"size="xs"/>
68-
}elseif(isCurrent){
69-
// current icon`
70-
icon=<Icontype="minus"size="xs"/>
71-
}else{
72-
// upcoming
73-
disabled=true
74-
icon=<Icontype="lock"size="xs"/>
75-
}
76-
return(
77-
<Menu.Itemkey={level.id}disabled={disabled}onSelect={()=>setMenuContent(level.id)}>
78-
{icon}&nbsp;&nbsp;&nbsp;{level.title}
79-
</Menu.Item>
80-
)
81-
})}
82-
</Menu>
83-
)
84-
8546
return(
8647
<Level
8748
title={title}
8849
content={content}
89-
menu={menu}
50+
menu={
51+
<ContentMenu
52+
tutorial={tutorial}
53+
position={position}
54+
progress={progress}
55+
setTitle={setTitle}
56+
setContent={setContent}
57+
/>
58+
}
9059
index={tutorial.levels.findIndex((l:TT.Level)=>l.id===position.levelId)}
9160
steps={steps}
9261
status={progress.levels[position.levelId] ?'COMPLETE' :'ACTIVE'}

‎web-app/src/services/state/actions/context.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as TT from 'typings/tutorial'
33
import{assign,send,ActionFunctionMap}from'xstate'
44
import*asselectorsfrom'../../selectors'
55
importonErrorfrom'../../../services/sentry/onError'
6+
importloggerfrom'../../../services/logger'
67

78
constcontextActions:ActionFunctionMap<T.MachineContext,T.MachineEvent>={
89
//@ts-ignore
@@ -15,25 +16,20 @@ const contextActions: ActionFunctionMap<T.MachineContext, T.MachineEvent> = {
1516
},
1617
}),
1718
//@ts-ignore
18-
storeContinuedTutorial:assign({
19-
env:(context:T.MachineContext,event:T.MachineEvent)=>{
20-
return{
19+
loadContinuedTutorial:assign((context:T.MachineContext,event:T.MachineEvent):any=>{
20+
return{
21+
env:{
2122
...context.env,
2223
...event.payload.env,
23-
}
24-
},
25-
tutorial:(context:T.MachineContext,event:T.MachineEvent)=>{
26-
returnevent.payload.tutorial
27-
},
28-
progress:(context:T.MachineContext,event:T.MachineEvent)=>{
29-
returnevent.payload.progress
30-
},
31-
position:(context:T.MachineContext,event:T.MachineEvent)=>{
32-
returnevent.payload.position
33-
},
24+
},
25+
tutorial:event.payload.tutorial,
26+
progress:event.payload.progress,
27+
position:event.payload.position,
28+
}
3429
}),
30+
3531
//@ts-ignore
36-
startNewTutorial:assign({
32+
initProgressPosition:assign({
3733
position:(context:T.MachineContext,event:T.MachineEvent):any=>{
3834
constposition:T.Position=selectors.initialPosition(context)
3935
returnposition
@@ -119,8 +115,7 @@ const contextActions: ActionFunctionMap<T.MachineContext, T.MachineEvent> = {
119115
//@ts-ignore
120116
updatePosition:assign({
121117
position:(context:T.MachineContext,event:T.MachineEvent):any=>{
122-
const{ position}=event.payload
123-
returnposition
118+
returnevent.payload
124119
},
125120
}),
126121
loadNext:send(
@@ -140,7 +135,7 @@ const contextActions: ActionFunctionMap<T.MachineContext, T.MachineEvent> = {
140135
// NEXT STEP
141136
if(hasNextStep){
142137
constnextPosition={ ...position,stepId:steps[stepIndex+1].id}
143-
return{type:'NEXT_STEP',payload:{position:nextPosition}}
138+
return{type:'NEXT_STEP',payload:nextPosition}
144139
}
145140

146141
// has next level?
@@ -164,7 +159,7 @@ const contextActions: ActionFunctionMap<T.MachineContext, T.MachineEvent> = {
164159
levelId:nextLevel.id,
165160
stepId:nextLevel.steps[0].id,
166161
}
167-
return{type:'NEXT_LEVEL',payload:{position:nextPosition}}
162+
return{type:'NEXT_LEVEL',payload:nextPosition}
168163
}
169164

170165
// COMPLETED
@@ -230,8 +225,9 @@ const contextActions: ActionFunctionMap<T.MachineContext, T.MachineEvent> = {
230225
error:():any=>null,
231226
}),
232227
//@ts-ignore
233-
checkEmptySteps:send((context:T.MachineContext)=>{
228+
checkLevelCompleted:send((context:T.MachineContext)=>{
234229
// no step id indicates no steps to complete
230+
logger(context.position)
235231
return{
236232
type:context.position.stepId===null ?'START_COMPLETED_LEVEL' :'START_LEVEL',
237233
}

‎web-app/src/services/state/machine.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const createMachine = (options: any) => {
6464
},
6565
LOAD_STORED_TUTORIAL:{
6666
target:'Start',
67-
actions:['storeContinuedTutorial'],
67+
actions:['loadContinuedTutorial'],
6868
},
6969
START_NEW_TUTORIAL:{
7070
target:'Start',
@@ -97,7 +97,7 @@ export const createMachine = (options: any) => {
9797
on:{
9898
NEW_TUTORIAL:'ValidateSetup',
9999
CONTINUE_TUTORIAL:{
100-
target:'#tutorial-level',
100+
target:'#tutorial',
101101
actions:['continueConfig'],
102102
},
103103
CONTINUE_FAILED:{
@@ -127,7 +127,7 @@ export const createMachine = (options: any) => {
127127
},
128128
},
129129
StartTutorial:{
130-
onEntry:['startNewTutorial'],
130+
onEntry:['initProgressPosition'],
131131
after:{
132132
0:'#tutorial',
133133
},
@@ -157,7 +157,7 @@ export const createMachine = (options: any) => {
157157
initial:'Load',
158158
states:{
159159
Load:{
160-
onEntry:['loadLevel','loadStep','checkEmptySteps'],
160+
onEntry:['loadLevel','loadStep','checkLevelCompleted'],
161161
on:{
162162
START_LEVEL:'Normal',
163163
START_COMPLETED_LEVEL:'LevelComplete',
@@ -214,9 +214,9 @@ export const createMachine = (options: any) => {
214214
onEntry:['updateLevelProgress'],
215215
onExit:['syncLevelProgress'],
216216
on:{
217-
LEVEL_NEXT:{
217+
NEXT_LEVEL:{
218218
target:'#tutorial-load-next',
219-
actions:['testClear'],
219+
actions:['testClear','updatePosition'],
220220
},
221221
},
222222
},

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp