@@ -25,6 +25,112 @@ 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+
28134const Model : ModelType = {
29135 namespace : 'workshop' ,
30136 state : {
@@ -41,7 +147,7 @@ const Model: ModelType = {
41147 * loadRepo ( { payload } , { put, select } ) {
42148 yield router . navigate ( '/home' )
43149
44- toast . info ( `loading ${ payload . name } / ${ payload . branch } ` )
150+ toast . warn ( 'USING MOCK DATA FOR TESTING' , { autoClose : 3000 } )
45151
46152 yield put ( {
47153 type : 'loading/save' ,
@@ -52,56 +158,8 @@ const Model: ModelType = {
52158
53159 const { list, detail } = yield select ( ( state ) => state . workshop )
54160
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- }
161+ // Inject mock data
162+ const data = mockApiData
105163
106164 const repoId = `${ payload . name } -${ payload . branch } `
107165
@@ -191,6 +249,159 @@ const Model: ModelType = {
191249 trackMatomoEvent ( remixClient , { category : 'learneth' , action : 'load_repo' , name : payload . name , isClick : false } )
192250 }
193251 } ,
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+ // },
194405 * resetAll ( { payload } , { put } ) {
195406 yield put ( {
196407 type : 'workshop/save' ,
0 commit comments