@@ -25,112 +25,6 @@ export const repoMap = {
2525 } ,
2626}
2727
28- // This data simulates the API response and includes 'priority'
29- const mockApiData = {
30- ids : [
31- 'basics' , 'circom-hash-checker' , 'er721Auction' , 'test-no-priority-Z' ,
32- 'test-same-priority-A' , 'test-no-priority-A' , 'advanced-prio-1' ,
33- 'advanced-no-prio-B' , 'advanced-prio-2' , 'advanced-no-prio-A'
34- ] ,
35- entities : {
36- // --- LEVEL 1 (Beginner) ---
37- // Prio: 100
38- 'basics' : {
39- id : 'basics' ,
40- level : 1 ,
41- name : 'L1 - Basics of Remix (Prio 100)' ,
42- description : { content : 'Should be 1st in Level 1.' } ,
43- metadata : { data : { id : 'basics' , level : 1 , name : 'L1 - Basics of Remix (Prio 100)' , tags : [ 'Remix' ] , priority : 100 } } ,
44- steps : [ ]
45- } ,
46- // Prio: 200
47- 'test-same-priority-A' : {
48- id : 'test-same-priority-A' ,
49- level : 1 ,
50- name : 'L1 - AAA Same Priority (Prio 200)' ,
51- description : { content : 'Should be 2nd in Level 1 (Same prio as Hash Checker, but name "AAA" comes first).' } ,
52- metadata : { data : { id : 'test-same-priority-A' , level : 1 , name : 'L1 - AAA Same Priority (Prio 200)' , tags : [ 'Test' ] , priority : 200 } } ,
53- steps : [ ]
54- } ,
55- // Prio: 200
56- 'circom-hash-checker' : {
57- id : 'circom-hash-checker' ,
58- level : 1 ,
59- name : 'L1 - Hash Checker Tutorial (Prio 200)' ,
60- description : { content : 'Should be 3rd in Level 1 (Same prio as "AAA", but "Hash" comes after).' } ,
61- metadata : { data : { id : 'circom-hash-checker' , level : 1 , name : 'L1 - Hash Checker Tutorial (Prio 200)' , tags : [ 'Circom' , 'Remix-IDE' ] , priority : 200 } } ,
62- steps : [ ]
63- } ,
64- // No Prio
65- 'test-no-priority-A' : {
66- id : 'test-no-priority-A' ,
67- level : 1 ,
68- name : 'L1 - Alpha No Priority (No Prio)' ,
69- description : { content : 'Should be 4th in Level 1 (Comes after all prioritized items. "Alpha" comes before "Zeta").' } ,
70- metadata : { data : { id : 'test-no-priority-A' , level : 1 , name : 'L1 - Alpha No Priority (No Prio)' , tags : [ 'Test' ] } } , // no priority
71- steps : [ ]
72- } ,
73- // No Prio
74- 'test-no-priority-Z' : {
75- id : 'test-no-priority-Z' ,
76- level : 1 ,
77- name : 'L1 - Zeta No Priority (No Prio)' ,
78- description : { content : 'Should be 5th (Last) in Level 1 (Comes after all prioritized items. "Zeta" comes after "Alpha").' } ,
79- metadata : { data : { id : 'test-no-priority-Z' , level : 1 , name : 'L1 - Zeta No Priority (No Prio)' , tags : [ 'Test' ] } } , // no priority
80- steps : [ ]
81- } ,
82-
83- // --- LEVEL 2 (Intermediate) ---
84- // Prio: 100
85- 'er721Auction' : {
86- id : 'er721Auction' ,
87- level : 2 ,
88- name : 'L2 - NFT Auction Contract (Prio 100)' ,
89- description : { content : 'Should be 1st in Level 2.' } ,
90- metadata : { data : { id : 'er721Auction' , level : 2 , name : 'L2 - NFT Auction Contract (Prio 100)' , tags : [ 'Solidity' , 'NFT' ] , priority : 100 } } ,
91- steps : [ ]
92- } ,
93-
94- // --- LEVEL 3 (Advanced) ---
95- // Prio: 100
96- 'advanced-prio-1' : {
97- id : 'advanced-prio-1' ,
98- level : 3 ,
99- name : 'L3 - Advanced Topic 1 (Prio 100)' ,
100- description : { content : 'Should be 1st in Level 3.' } ,
101- metadata : { data : { id : 'advanced-prio-1' , level : 3 , name : 'L3 - Advanced Topic 1 (Prio 100)' , tags : [ 'Advanced' ] , priority : 100 } } ,
102- steps : [ ]
103- } ,
104- // Prio: 300
105- 'advanced-prio-2' : {
106- id : 'advanced-prio-2' ,
107- level : 3 ,
108- name : 'L3 - Advanced Topic 2 (Prio 300)' ,
109- description : { content : 'Should be 2nd in Level 3.' } ,
110- metadata : { data : { id : 'advanced-prio-2' , level : 3 , name : 'L3 - Advanced Topic 2 (Prio 300)' , tags : [ 'Advanced' ] , priority : 300 } } ,
111- steps : [ ]
112- } ,
113- // No Prio
114- 'advanced-no-prio-A' : {
115- id : 'advanced-no-prio-A' ,
116- level : 3 ,
117- name : 'L3 - Adv Topic A (No Prio)' ,
118- description : { content : 'Should be 3rd in Level 3 (After prioritized items. "A" comes before "B").' } ,
119- metadata : { data : { id : 'advanced-no-prio-A' , level : 3 , name : 'L3 - Adv Topic A (No Prio)' , tags : [ 'Advanced' ] } } , // no priority
120- steps : [ ]
121- } ,
122- // No Prio
123- 'advanced-no-prio-B' : {
124- id : 'advanced-no-prio-B' ,
125- level : 3 ,
126- name : 'L3 - Adv Topic B (No Prio)' ,
127- description : { content : 'Should be 4th (Last) in Level 3 (After prioritized items. "B" comes after "A").' } ,
128- metadata : { data : { id : 'advanced-no-prio-B' , level : 3 , name : 'L3 - Adv Topic B (No Prio)' , tags : [ 'Advanced' ] } } , // no priority
129- steps : [ ]
130- }
131- }
132- }
133-
13428const Model : ModelType = {
13529 namespace : 'workshop' ,
13630 state : {
@@ -147,7 +41,7 @@ const Model: ModelType = {
14741 * loadRepo ( { payload } , { put, select } ) {
14842 yield router . navigate ( '/home' )
14943
150- toast . warn ( 'USING MOCK DATA FOR TESTING' , { autoClose : 3000 } )
44+ toast . info ( `loading ${ payload . name } / ${ payload . branch } ` )
15145
15246 yield put ( {
15347 type : 'loading/save' ,
@@ -158,8 +52,56 @@ const Model: ModelType = {
15852
15953 const { list, detail } = yield select ( ( state ) => state . workshop )
16054
161- // Inject mock data
162- const data = mockApiData
55+ const url = `${ apiUrl } /clone/${ encodeURIComponent ( payload . name ) } /${ payload . branch } ?${ Math . random ( ) } `
56+
57+ let data
58+ try {
59+ const response = yield axios . get ( url )
60+ data = response . data
61+ } catch ( error ) {
62+ console . error ( 'Failed to load workshop:' , error )
63+
64+ // Dismiss loading toast and show error
65+ toast . dismiss ( )
66+
67+ // Extract detailed error message from response
68+ let errorMessage = 'Failed to load workshop'
69+ if ( error . response ?. data ) {
70+ // If the response contains plain text error details (like in the screenshot)
71+ if ( typeof error . response . data === 'string' ) {
72+ errorMessage = error . response . data
73+ }
74+ // If the response has a structured error message
75+ else if ( error . response . data . message ) {
76+ errorMessage = error . response . data . message
77+ }
78+ // If the response has error details
79+ else if ( error . response . data . error ) {
80+ errorMessage = error . response . data . error
81+ }
82+ }
83+ // Fallback to axios error message or generic error
84+ else if ( error . message ) {
85+ errorMessage = error . message
86+ } else {
87+ errorMessage = 'Network error occurred'
88+ }
89+
90+ toast . error ( errorMessage )
91+
92+ // Clean up loading state
93+ yield put ( {
94+ type : 'loading/save' ,
95+ payload : {
96+ screen : false ,
97+ } ,
98+ } )
99+
100+ // Track error event
101+ trackMatomoEvent ( remixClient , { category : 'learneth' , action : 'load_repo_error' , name : `${ payload . name } /${ payload . branch } ` , isClick : false } )
102+
103+ return // Exit early on error
104+ }
163105
164106 const repoId = `${ payload . name } -${ payload . branch } `
165107
@@ -249,159 +191,6 @@ const Model: ModelType = {
249191 trackMatomoEvent ( remixClient , { category : 'learneth' , action : 'load_repo' , name : payload . name , isClick : false } )
250192 }
251193 } ,
252- // *loadRepo({ payload }, { put, select }) {
253- // yield router.navigate('/home')
254-
255- // toast.info(`loading ${payload.name}/${payload.branch}`)
256-
257- // yield put({
258- // type: 'loading/save',
259- // payload: {
260- // screen: true,
261- // },
262- // })
263-
264- // const { list, detail } = yield select((state) => state.workshop)
265-
266- // const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${payload.branch}?${Math.random()}`
267-
268- // let data
269- // try {
270- // const response = yield axios.get(url)
271- // data = response.data
272- // } catch (error) {
273- // console.error('Failed to load workshop:', error)
274-
275- // // Dismiss loading toast and show error
276- // toast.dismiss()
277-
278- // // Extract detailed error message from response
279- // let errorMessage = 'Failed to load workshop'
280- // if (error.response?.data) {
281- // // If the response contains plain text error details (like in the screenshot)
282- // if (typeof error.response.data === 'string') {
283- // errorMessage = error.response.data
284- // }
285- // // If the response has a structured error message
286- // else if (error.response.data.message) {
287- // errorMessage = error.response.data.message
288- // }
289- // // If the response has error details
290- // else if (error.response.data.error) {
291- // errorMessage = error.response.data.error
292- // }
293- // }
294- // // Fallback to axios error message or generic error
295- // else if (error.message) {
296- // errorMessage = error.message
297- // } else {
298- // errorMessage = 'Network error occurred'
299- // }
300-
301- // toast.error(errorMessage)
302-
303- // // Clean up loading state
304- // yield put({
305- // type: 'loading/save',
306- // payload: {
307- // screen: false,
308- // },
309- // })
310-
311- // // Track error event
312- // trackMatomoEvent(remixClient, { category: 'learneth', action: 'load_repo_error', name: `${payload.name}/${payload.branch}`, isClick: false })
313-
314- // return // Exit early on error
315- // }
316-
317- // const repoId = `${payload.name}-${payload.branch}`
318-
319- // for (let i = 0; i < data.ids.length; i++) {
320- // const {
321- // steps,
322- // metadata: {
323- // data: { steps: metadataSteps },
324- // },
325- // } = data.entities[data.ids[i]]
326-
327- // let newSteps = []
328-
329- // if (metadataSteps) {
330- // newSteps = metadataSteps.map((step: any) => {
331- // return {
332- // ...steps.find((item: any) => item.name === step.path),
333- // name: step.name,
334- // }
335- // })
336- // } else {
337- // newSteps = steps.map((step: any) => ({
338- // ...step,
339- // name: step.name.replace('_', ' '),
340- // }))
341- // }
342-
343- // const stepKeysWithFile = ['markdown', 'solidity', 'test', 'answer', 'js', 'vy']
344-
345- // for (let j = 0; j < newSteps.length; j++) {
346- // const step = newSteps[j]
347- // for (let k = 0; k < stepKeysWithFile.length; k++) {
348- // const key = stepKeysWithFile[k]
349- // if (step[key]) {
350- // try {
351- // step[key].content = null // we load this later
352- // } catch (error) {
353- // console.error(error)
354- // }
355- // }
356- // }
357- // }
358- // data.entities[data.ids[i]].steps = newSteps
359- // }
360-
361- // const workshopState = {
362- // detail: {
363- // ...detail,
364- // [repoId]: {
365- // ...data,
366- // group: groupBy(
367- // data.ids.map((id: string) => pick(data.entities[id], ['level', 'id'])),
368- // (item: any) => item.level
369- // ),
370- // ...payload,
371- // },
372- // },
373- // list: list.map(item => `${item.name}/${item.branch}`).includes(`${payload.name}/${payload.branch}`) ? list : [...list, payload],
374- // selectedId: repoId,
375- // }
376- // yield put({
377- // type: 'workshop/save',
378- // payload: workshopState,
379- // })
380-
381- // toast.dismiss()
382- // yield put({
383- // type: 'loading/save',
384- // payload: {
385- // screen: false,
386- // },
387- // })
388-
389- // if (payload.id) {
390- // const { detail, selectedId } = workshopState
391- // const { ids, entities } = detail[selectedId]
392- // for (let i = 0; i < ids.length; i++) {
393- // const entity = entities[ids[i]]
394- // if (entity.metadata.data.id === payload.id || i + 1 === payload.id) {
395- // yield router.navigate(`/list?id=${ids[i]}`)
396- // break
397- // }
398- // }
399- // }
400- // // we don't need to track the default repos
401- // if (payload.name !== 'ethereum/remix-workshops' && payload.name !== 'remix-project-org/remix-workshops') {
402- // trackMatomoEvent(remixClient, { category: 'learneth', action: 'load_repo', name: payload.name, isClick: false })
403- // }
404- // },
405194 * resetAll ( { payload } , { put } ) {
406195 yield put ( {
407196 type : 'workshop/save' ,
0 commit comments