@learnpack/learnpack 5.0.308 → 5.0.310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +409 -409
  2. package/lib/commands/audit.js +15 -15
  3. package/lib/commands/breakToken.js +19 -19
  4. package/lib/commands/clean.js +3 -3
  5. package/lib/commands/logout.js +3 -3
  6. package/lib/commands/serve.js +16 -16
  7. package/lib/creatorDist/assets/{index-B37w_ZhT.js → index-BI7U47zy.js} +13186 -13013
  8. package/lib/creatorDist/index.html +1 -1
  9. package/lib/managers/config/index.js +77 -77
  10. package/lib/utils/creatorUtilities.js +14 -14
  11. package/lib/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  12. package/lib/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
  13. package/lib/utils/templates/scorm/adlcp_rootv1p2.xsd +110 -110
  14. package/lib/utils/templates/scorm/config/index.html +209 -209
  15. package/lib/utils/templates/scorm/ims_xml.xsd +1 -1
  16. package/lib/utils/templates/scorm/imscp_rootv1p1p2.xsd +345 -345
  17. package/lib/utils/templates/scorm/imsmanifest.xml +38 -38
  18. package/lib/utils/templates/scorm/imsmd_rootv1p2p1.xsd +573 -573
  19. package/package.json +1 -1
  20. package/src/commands/audit.ts +487 -487
  21. package/src/commands/breakToken.ts +67 -67
  22. package/src/commands/clean.ts +30 -30
  23. package/src/commands/logout.ts +38 -38
  24. package/src/commands/publish.ts +517 -517
  25. package/src/commands/serve.ts +3179 -3179
  26. package/src/commands/start.ts +333 -333
  27. package/src/commands/translate.ts +123 -123
  28. package/src/creator/README.md +54 -54
  29. package/src/creator/package-lock.json +6621 -6621
  30. package/src/creator/package.json +55 -55
  31. package/src/creator/src/App.tsx +611 -608
  32. package/src/creator/src/components/FileUploader.tsx +340 -302
  33. package/src/creator/src/components/Icon.tsx +18 -18
  34. package/src/creator/src/components/LessonItem.tsx +152 -152
  35. package/src/creator/src/components/Login.tsx +259 -259
  36. package/src/creator/src/components/ParamsChecker.tsx +25 -25
  37. package/src/creator/src/components/Uploader.tsx +3 -6
  38. package/src/creator/src/components/syllabus/ContentIndex.tsx +323 -323
  39. package/src/creator/src/components/syllabus/SyllabusEditor.tsx +341 -337
  40. package/src/creator/src/i18n.ts +28 -28
  41. package/src/creator/src/locales/en.json +139 -138
  42. package/src/creator/src/locales/es.json +139 -138
  43. package/src/creator/src/utils/configTypes.ts +122 -122
  44. package/src/creator/src/utils/constants.ts +13 -13
  45. package/src/creator/src/utils/creatorUtils.ts +46 -46
  46. package/src/creator/src/utils/eventBus.ts +2 -2
  47. package/src/creator/src/utils/lib.ts +172 -172
  48. package/src/creator/src/utils/rigo.ts +1 -1
  49. package/src/creator/src/utils/socket.ts +61 -61
  50. package/src/creator/src/utils/store.ts +222 -222
  51. package/src/creator/src/vite-env.d.ts +1 -1
  52. package/src/creator/vite.config.ts +13 -13
  53. package/src/creatorDist/assets/{index-B37w_ZhT.js → index-BI7U47zy.js} +13186 -13013
  54. package/src/creatorDist/index.html +1 -1
  55. package/src/managers/config/defaults.ts +49 -49
  56. package/src/managers/config/exercise.ts +364 -364
  57. package/src/managers/config/index.ts +775 -775
  58. package/src/managers/file.ts +236 -236
  59. package/src/managers/server/routes.ts +554 -554
  60. package/src/managers/telemetry.ts +188 -188
  61. package/src/models/action.ts +13 -13
  62. package/src/models/config-manager.ts +28 -28
  63. package/src/models/config.ts +106 -106
  64. package/src/models/exercise-obj.ts +30 -30
  65. package/src/models/session.ts +39 -39
  66. package/src/models/socket.ts +61 -61
  67. package/src/models/status.ts +16 -16
  68. package/src/ui/_app/app.css +1 -1
  69. package/src/ui/_app/app.js +477 -407
  70. package/src/ui/app.tar.gz +0 -0
  71. package/src/utils/BaseCommand.ts +56 -56
  72. package/src/utils/api.ts +665 -665
  73. package/src/utils/audit.ts +392 -392
  74. package/src/utils/checkNotInstalled.ts +267 -267
  75. package/src/utils/convertCreds.js +34 -34
  76. package/src/utils/creatorUtilities.ts +504 -504
  77. package/src/utils/export/README.md +178 -178
  78. package/src/utils/incrementVersion.js +74 -74
  79. package/src/utils/misc.ts +58 -58
  80. package/src/utils/sidebarGenerator.ts +195 -195
  81. package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  82. package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
  83. package/src/utils/templates/scorm/adlcp_rootv1p2.xsd +110 -110
  84. package/src/utils/templates/scorm/config/index.html +209 -209
  85. package/src/utils/templates/scorm/ims_xml.xsd +1 -1
  86. package/src/utils/templates/scorm/imscp_rootv1p1p2.xsd +345 -345
  87. package/src/utils/templates/scorm/imsmanifest.xml +38 -38
  88. package/src/utils/templates/scorm/imsmd_rootv1p2p1.xsd +573 -573
@@ -1,337 +1,341 @@
1
- import React, { useState, useEffect } from "react"
2
- import { useShallow } from "zustand/react/shallow"
3
- import useStore from "../../utils/store"
4
- import { publicInteractiveCreation } from "../../utils/rigo"
5
- import {
6
- parseLesson,
7
- // useConsumableCall,
8
- validateTokens,
9
- checkParams,
10
- loginWithToken,
11
- createCourse,
12
- isSlugAvailable,
13
- // reWriteTitle,
14
- useConsumableCall,
15
- isValidRigoToken,
16
- isValidPublicToken,
17
- } from "../../utils/lib"
18
-
19
- import Loader from "../Loader"
20
- import { TMessage } from "../Message"
21
- import { Lesson } from "../LessonItem"
22
- import { ConsumablesManager } from "../ConsumablesManager"
23
- import toast from "react-hot-toast"
24
- import { ContentIndex } from "./ContentIndex"
25
- import { Sidebar } from "./Sidebar"
26
- import Login from "../Login"
27
- import { useNavigate } from "react-router"
28
- import { ParamsChecker } from "../ParamsChecker"
29
- import { randomUUID } from "../../utils/creatorUtils"
30
- import { RIGO_FLOAT_GIF } from "../../utils/constants"
31
- import { useTranslation } from "react-i18next"
32
- import NotificationListener from "../NotificationListener"
33
-
34
- const SyllabusEditor: React.FC = () => {
35
- const navigate = useNavigate()
36
- const { i18n } = useTranslation()
37
-
38
- const {
39
- history,
40
- auth,
41
- setAuth,
42
- push,
43
- cleanAll,
44
- messages,
45
- setMessages,
46
- technologies,
47
- mode,
48
- } = useStore(
49
- useShallow((state) => ({
50
- history: state.history,
51
- auth: state.auth,
52
- setAuth: state.setAuth,
53
- push: state.push,
54
- cleanAll: state.cleanAll,
55
- messages: state.messages,
56
- // formState: state.formState,
57
- setMessages: state.setMessages,
58
- technologies: state.technologies,
59
- mode: state.mode,
60
- }))
61
- )
62
-
63
- const [isGenerating, setIsGenerating] = useState(false)
64
- const [showLoginModal, setShowLoginModal] = useState(false)
65
- const [isThinking, setIsThinking] = useState(false)
66
- const [notificationId, setNotificationId] = useState<string>("")
67
-
68
- const syllabus = history[history.length - 1]
69
-
70
- useEffect(() => {
71
- if (!syllabus) {
72
- navigate("/creator", { replace: true })
73
- }
74
- }, [syllabus, navigate])
75
-
76
- useEffect(() => {
77
- ;(async () => {
78
- const { token } = checkParams(["token"])
79
- if (token) {
80
- const user = await loginWithToken(token)
81
- if (user) {
82
- setAuth({
83
- bcToken: token,
84
- userId: user.id,
85
- rigoToken: user.rigobot.key,
86
- user,
87
- publicToken: "",
88
- })
89
- }
90
- }
91
- })()
92
- checkSlug()
93
- }, [])
94
-
95
- const checkSlug = async () => {
96
- if (!syllabus.courseInfo.title) {
97
- toast.error("Please provide a title for the course")
98
- return
99
- }
100
-
101
- let newSlug = syllabus.courseInfo.slug
102
- let isAvailable = await isSlugAvailable(syllabus.courseInfo.slug)
103
-
104
- while (!isAvailable) {
105
- if (newSlug.length > 50) {
106
- newSlug = newSlug.slice(0, 44)
107
- }
108
- newSlug = newSlug + "-" + randomUUID()
109
- newSlug = newSlug.slice(0, 50)
110
- isAvailable = await isSlugAvailable(newSlug)
111
- }
112
-
113
- push({
114
- ...syllabus,
115
- courseInfo: {
116
- ...syllabus.courseInfo,
117
- slug: newSlug,
118
- },
119
- })
120
- }
121
-
122
- const sendPrompt = async (prompt: string) => {
123
- setIsThinking(true)
124
-
125
- try {
126
- let isAuthenticated = false
127
- let tokenType = ""
128
- let tokenToUse = ""
129
- if (auth.rigoToken) {
130
- const isRigoTokenValid = await isValidRigoToken(auth.rigoToken)
131
- if (isRigoTokenValid) {
132
- isAuthenticated = true
133
- tokenType = "rigo"
134
- tokenToUse = auth.rigoToken
135
- } else {
136
- setAuth({
137
- ...auth,
138
- rigoToken: "",
139
- bcToken: "",
140
- userId: "",
141
- user: null,
142
- })
143
- }
144
- }
145
-
146
- if (auth.publicToken && !isAuthenticated) {
147
- const isPublicTokenValid = await isValidPublicToken(auth.publicToken)
148
- if (isPublicTokenValid) {
149
- isAuthenticated = true
150
- tokenType = "public"
151
- tokenToUse = auth.publicToken
152
- }
153
- }
154
-
155
- if (!isAuthenticated) {
156
- setShowLoginModal(true)
157
- return
158
- }
159
-
160
- setMessages([
161
- ...messages,
162
- { type: "user", content: prompt },
163
- { type: "assistant", content: "" },
164
- ])
165
-
166
- const lessonsText = JSON.stringify(syllabus.lessons)
167
-
168
- const res = await publicInteractiveCreation(
169
- {
170
- courseInfo:
171
- JSON.stringify(syllabus.courseInfo) +
172
- `\nThe following technologies are available, choose up to 3 from the following list: <techs>${technologies
173
- .filter((t) => t.lang === syllabus.courseInfo.language)
174
- .map((t) => t.slug)
175
- .join(", ")}</techs> \nThe following lessons are already in the syllabus: ${lessonsText}
176
-
177
- You must NEVER delete lessons that are marked as locked.
178
- `,
179
- prevInteractions:
180
- messages
181
- .map((message) => `${message.type}: ${message.content}`)
182
- .join("\n") + `\nUSER: ${prompt}`,
183
- },
184
- tokenToUse,
185
- syllabus?.courseInfo?.purpose || "learnpack-lesson-writer",
186
- tokenType === "rigo" ? false : true
187
- )
188
-
189
- setNotificationId(res.notificationId)
190
- } catch (error) {
191
- console.error(error)
192
- const newMessages = [...messages]
193
- newMessages.pop()
194
- setMessages(newMessages as TMessage[])
195
- setIsThinking(false)
196
- }
197
- }
198
-
199
- const handleSubmit = async () => {
200
- if (!auth.bcToken || !auth.rigoToken) {
201
- setShowLoginModal(true)
202
- return
203
- }
204
-
205
- if (!syllabus.courseInfo.title) {
206
- toast.error("Please provide a title for the course")
207
- return
208
- }
209
-
210
- let tokenToUse = auth.rigoToken
211
- const onValidRigoToken = (rigotoken: string) => {
212
- setAuth({
213
- ...auth,
214
- rigoToken: rigotoken,
215
- })
216
- tokenToUse = rigotoken
217
- }
218
- const isValid = await validateTokens(auth.bcToken, onValidRigoToken)
219
- if (!isValid) {
220
- setShowLoginModal(true)
221
- return
222
- }
223
- const success = await useConsumableCall(
224
- auth.bcToken,
225
- "ai-course-generation"
226
- )
227
- if (!success) {
228
- toast.error(
229
- "You don't have enough credits to generate a course! Please add more credits to your account."
230
- )
231
- toast.loading("You will be redirected to the settings page in 5 seconds.")
232
- setTimeout(() => {
233
- window.location.href =
234
- "https://learnpack.co/settings?token=" + auth.bcToken
235
- }, 5000)
236
- return
237
- }
238
-
239
- setIsGenerating(true)
240
-
241
- const timeout = setTimeout(() => {
242
- cleanAll()
243
- window.location.href = `/preview/${syllabus.courseInfo.slug}?token=${auth.bcToken}&language=${syllabus.courseInfo.language}&mode=${mode}`
244
- }, 8000)
245
- try {
246
- await createCourse(syllabus, tokenToUse, auth.bcToken)
247
- } catch (error) {
248
- console.error("Failed to create course:", error)
249
- clearTimeout(timeout)
250
- setIsGenerating(false)
251
- }
252
- }
253
-
254
- if (!syllabus) return null
255
-
256
- console.log(syllabus.courseInfo)
257
-
258
- return isGenerating ? (
259
- <>
260
- <Loader
261
- listeningTo="course-generation"
262
- icon={<img src={RIGO_FLOAT_GIF} alt="rigo" className="w-20 h-20" />}
263
- initialBuffer="🚀 Starting course generation..."
264
- text="Learnpack is setting up your tutorial.
265
- It may take a moment..."
266
- />
267
- </>
268
- ) : (
269
- <div className="flex w-full bg-white rounded-md shadow-md overflow-hidden h-screen ">
270
- <ParamsChecker />
271
- <NotificationListener
272
- onNotification={(res) => {
273
- const lessons: Lesson[] = res.parsed.listOfSteps.map((step: any) =>
274
- parseLesson(step, syllabus.lessons)
275
- )
276
- push({
277
- ...syllabus,
278
- lessons: lessons,
279
- courseInfo: {
280
- ...syllabus.courseInfo,
281
- title: res.parsed.title || syllabus.courseInfo.title,
282
- description:
283
- res.parsed.description || syllabus.courseInfo.description,
284
- language:
285
- res.parsed.languageCode || syllabus.courseInfo.language || "en",
286
- technologies:
287
- res.parsed.technologies.length > 0
288
- ? res.parsed.technologies
289
- : syllabus.courseInfo.technologies || [],
290
- },
291
- })
292
-
293
- if (res.parsed.languageCode) {
294
- i18n.changeLanguage(res.parsed.languageCode)
295
- }
296
-
297
- setMessages((prev) => [
298
- ...prev.filter((m) => Boolean(m.content)),
299
- {
300
- type: "assistant",
301
- content: res.parsed.aiMessage,
302
- },
303
- ])
304
- setIsThinking(false)
305
- setNotificationId("")
306
- }}
307
- notificationId={notificationId}
308
- />
309
- {showLoginModal && (
310
- <Login
311
- onFinish={() => {
312
- setShowLoginModal(false)
313
- }}
314
- />
315
- )}
316
-
317
- <ConsumablesManager />
318
-
319
- <Sidebar
320
- // messages={messages}
321
- sendPrompt={sendPrompt}
322
- handleSubmit={handleSubmit}
323
- />
324
-
325
- <ContentIndex
326
- handleSubmit={handleSubmit}
327
- messages={messages}
328
- isThinking={isThinking}
329
- openLogin={() => {
330
- setShowLoginModal(true)
331
- }}
332
- />
333
- </div>
334
- )
335
- }
336
-
337
- export default SyllabusEditor
1
+ import React, { useState, useEffect } from "react"
2
+ import { useShallow } from "zustand/react/shallow"
3
+ import useStore from "../../utils/store"
4
+ import { publicInteractiveCreation } from "../../utils/rigo"
5
+ import {
6
+ parseLesson,
7
+ // useConsumableCall,
8
+ validateTokens,
9
+ checkParams,
10
+ loginWithToken,
11
+ createCourse,
12
+ isSlugAvailable,
13
+ // reWriteTitle,
14
+ useConsumableCall,
15
+ isValidRigoToken,
16
+ isValidPublicToken,
17
+ } from "../../utils/lib"
18
+
19
+ import Loader from "../Loader"
20
+ import { TMessage } from "../Message"
21
+ import { Lesson } from "../LessonItem"
22
+ import { ConsumablesManager } from "../ConsumablesManager"
23
+ import toast from "react-hot-toast"
24
+ import { ContentIndex } from "./ContentIndex"
25
+ import { Sidebar } from "./Sidebar"
26
+ import Login from "../Login"
27
+ import { useNavigate } from "react-router"
28
+ import { ParamsChecker } from "../ParamsChecker"
29
+ import { randomUUID } from "../../utils/creatorUtils"
30
+ import { RIGO_FLOAT_GIF } from "../../utils/constants"
31
+ import { useTranslation } from "react-i18next"
32
+ import NotificationListener from "../NotificationListener"
33
+
34
+ const SyllabusEditor: React.FC = () => {
35
+ const navigate = useNavigate()
36
+ const { i18n } = useTranslation()
37
+
38
+ const {
39
+ history,
40
+ auth,
41
+ setAuth,
42
+ push,
43
+ cleanAll,
44
+ messages,
45
+ setMessages,
46
+ technologies,
47
+ mode,
48
+ uploadedFiles,
49
+ } = useStore(
50
+ useShallow((state) => ({
51
+ history: state.history,
52
+ auth: state.auth,
53
+ setAuth: state.setAuth,
54
+ push: state.push,
55
+ cleanAll: state.cleanAll,
56
+ messages: state.messages,
57
+ // formState: state.formState,
58
+ setMessages: state.setMessages,
59
+ technologies: state.technologies,
60
+ mode: state.mode,
61
+ uploadedFiles: state.uploadedFiles,
62
+ }))
63
+ )
64
+
65
+ const [isGenerating, setIsGenerating] = useState(false)
66
+ const [showLoginModal, setShowLoginModal] = useState(false)
67
+ const [isThinking, setIsThinking] = useState(false)
68
+ const [notificationId, setNotificationId] = useState<string>("")
69
+
70
+ const syllabus = history[history.length - 1]
71
+
72
+ useEffect(() => {
73
+ if (!syllabus) {
74
+ navigate("/creator", { replace: true })
75
+ }
76
+ }, [syllabus, navigate])
77
+
78
+ useEffect(() => {
79
+ ;(async () => {
80
+ const { token } = checkParams(["token"])
81
+ if (token) {
82
+ const user = await loginWithToken(token)
83
+ if (user) {
84
+ setAuth({
85
+ bcToken: token,
86
+ userId: user.id,
87
+ rigoToken: user.rigobot.key,
88
+ user,
89
+ publicToken: "",
90
+ })
91
+ }
92
+ }
93
+ })()
94
+ checkSlug()
95
+ }, [])
96
+
97
+ const checkSlug = async () => {
98
+ if (!syllabus.courseInfo.title) {
99
+ toast.error("Please provide a title for the course")
100
+ return
101
+ }
102
+
103
+ let newSlug = syllabus.courseInfo.slug
104
+ let isAvailable = await isSlugAvailable(syllabus.courseInfo.slug)
105
+
106
+ while (!isAvailable) {
107
+ if (newSlug.length > 50) {
108
+ newSlug = newSlug.slice(0, 44)
109
+ }
110
+ newSlug = newSlug + "-" + randomUUID()
111
+ newSlug = newSlug.slice(0, 50)
112
+ isAvailable = await isSlugAvailable(newSlug)
113
+ }
114
+
115
+ push({
116
+ ...syllabus,
117
+ courseInfo: {
118
+ ...syllabus.courseInfo,
119
+ slug: newSlug,
120
+ },
121
+ })
122
+ }
123
+
124
+ const sendPrompt = async (prompt: string) => {
125
+ setIsThinking(true)
126
+
127
+ try {
128
+ let isAuthenticated = false
129
+ let tokenType = ""
130
+ let tokenToUse = ""
131
+ if (auth.rigoToken) {
132
+ const isRigoTokenValid = await isValidRigoToken(auth.rigoToken)
133
+ if (isRigoTokenValid) {
134
+ isAuthenticated = true
135
+ tokenType = "rigo"
136
+ tokenToUse = auth.rigoToken
137
+ } else {
138
+ setAuth({
139
+ ...auth,
140
+ rigoToken: "",
141
+ bcToken: "",
142
+ userId: "",
143
+ user: null,
144
+ })
145
+ }
146
+ }
147
+
148
+ if (auth.publicToken && !isAuthenticated) {
149
+ const isPublicTokenValid = await isValidPublicToken(auth.publicToken)
150
+ if (isPublicTokenValid) {
151
+ isAuthenticated = true
152
+ tokenType = "public"
153
+ tokenToUse = auth.publicToken
154
+ }
155
+ }
156
+
157
+ if (!isAuthenticated) {
158
+ setShowLoginModal(true)
159
+ return
160
+ }
161
+
162
+ setMessages([
163
+ ...messages,
164
+ { type: "user", content: prompt },
165
+ { type: "assistant", content: "" },
166
+ ])
167
+
168
+ const lessonsText = JSON.stringify(syllabus.lessons)
169
+
170
+ const res = await publicInteractiveCreation(
171
+ {
172
+ courseInfo:
173
+ JSON.stringify(syllabus.courseInfo) +
174
+ `\nThe following technologies are available, choose up to 3 from the following list: <techs>${technologies
175
+ .filter((t) => t.lang === syllabus.courseInfo.language)
176
+ .map((t) => t.slug)
177
+ .join(", ")}</techs> \nThe following lessons are already in the syllabus: ${lessonsText}
178
+
179
+
180
+ The following files have been uploaded by the user: ${uploadedFiles.map((f) => `<FILE name="${f.name}">${f.text}</FILE>`).join("\n")}
181
+ You must NEVER delete lessons that are marked as locked.
182
+ `,
183
+ prevInteractions:
184
+ messages
185
+ .map((message) => `${message.type}: ${message.content}`)
186
+ .join("\n") + `\nUSER: ${prompt}`,
187
+ },
188
+ tokenToUse,
189
+ syllabus?.courseInfo?.purpose || "learnpack-lesson-writer",
190
+ tokenType === "rigo" ? false : true
191
+ )
192
+
193
+ setNotificationId(res.notificationId)
194
+ } catch (error) {
195
+ console.error(error)
196
+ const newMessages = [...messages]
197
+ newMessages.pop()
198
+ setMessages(newMessages as TMessage[])
199
+ setIsThinking(false)
200
+ }
201
+ }
202
+
203
+ const handleSubmit = async () => {
204
+ if (!auth.bcToken || !auth.rigoToken) {
205
+ setShowLoginModal(true)
206
+ return
207
+ }
208
+
209
+ if (!syllabus.courseInfo.title) {
210
+ toast.error("Please provide a title for the course")
211
+ return
212
+ }
213
+
214
+ let tokenToUse = auth.rigoToken
215
+ const onValidRigoToken = (rigotoken: string) => {
216
+ setAuth({
217
+ ...auth,
218
+ rigoToken: rigotoken,
219
+ })
220
+ tokenToUse = rigotoken
221
+ }
222
+ const isValid = await validateTokens(auth.bcToken, onValidRigoToken)
223
+ if (!isValid) {
224
+ setShowLoginModal(true)
225
+ return
226
+ }
227
+ const success = await useConsumableCall(
228
+ auth.bcToken,
229
+ "ai-course-generation"
230
+ )
231
+ if (!success) {
232
+ toast.error(
233
+ "You don't have enough credits to generate a course! Please add more credits to your account."
234
+ )
235
+ toast.loading("You will be redirected to the settings page in 5 seconds.")
236
+ setTimeout(() => {
237
+ window.location.href =
238
+ "https://learnpack.co/settings?token=" + auth.bcToken
239
+ }, 5000)
240
+ return
241
+ }
242
+
243
+ setIsGenerating(true)
244
+
245
+ const timeout = setTimeout(() => {
246
+ cleanAll()
247
+ window.location.href = `/preview/${syllabus.courseInfo.slug}?token=${auth.bcToken}&language=${syllabus.courseInfo.language}&mode=${mode}`
248
+ }, 8000)
249
+ try {
250
+ await createCourse(syllabus, tokenToUse, auth.bcToken)
251
+ } catch (error) {
252
+ console.error("Failed to create course:", error)
253
+ clearTimeout(timeout)
254
+ setIsGenerating(false)
255
+ }
256
+ }
257
+
258
+ if (!syllabus) return null
259
+
260
+ console.log(syllabus.courseInfo)
261
+
262
+ return isGenerating ? (
263
+ <>
264
+ <Loader
265
+ listeningTo="course-generation"
266
+ icon={<img src={RIGO_FLOAT_GIF} alt="rigo" className="w-20 h-20" />}
267
+ initialBuffer="🚀 Starting course generation..."
268
+ text="Learnpack is setting up your tutorial.
269
+ It may take a moment..."
270
+ />
271
+ </>
272
+ ) : (
273
+ <div className="flex w-full bg-white rounded-md shadow-md overflow-hidden h-screen ">
274
+ <ParamsChecker />
275
+ <NotificationListener
276
+ onNotification={(res) => {
277
+ const lessons: Lesson[] = res.parsed.listOfSteps.map((step: any) =>
278
+ parseLesson(step, syllabus.lessons)
279
+ )
280
+ push({
281
+ ...syllabus,
282
+ lessons: lessons,
283
+ courseInfo: {
284
+ ...syllabus.courseInfo,
285
+ title: res.parsed.title || syllabus.courseInfo.title,
286
+ description:
287
+ res.parsed.description || syllabus.courseInfo.description,
288
+ language:
289
+ res.parsed.languageCode || syllabus.courseInfo.language || "en",
290
+ technologies:
291
+ res.parsed.technologies.length > 0
292
+ ? res.parsed.technologies
293
+ : syllabus.courseInfo.technologies || [],
294
+ },
295
+ })
296
+
297
+ if (res.parsed.languageCode) {
298
+ i18n.changeLanguage(res.parsed.languageCode)
299
+ }
300
+
301
+ setMessages((prev) => [
302
+ ...prev.filter((m) => Boolean(m.content)),
303
+ {
304
+ type: "assistant",
305
+ content: res.parsed.aiMessage,
306
+ },
307
+ ])
308
+ setIsThinking(false)
309
+ setNotificationId("")
310
+ }}
311
+ notificationId={notificationId}
312
+ />
313
+ {showLoginModal && (
314
+ <Login
315
+ onFinish={() => {
316
+ setShowLoginModal(false)
317
+ }}
318
+ />
319
+ )}
320
+
321
+ <ConsumablesManager />
322
+
323
+ <Sidebar
324
+ // messages={messages}
325
+ sendPrompt={sendPrompt}
326
+ handleSubmit={handleSubmit}
327
+ />
328
+
329
+ <ContentIndex
330
+ handleSubmit={handleSubmit}
331
+ messages={messages}
332
+ isThinking={isThinking}
333
+ openLogin={() => {
334
+ setShowLoginModal(true)
335
+ }}
336
+ />
337
+ </div>
338
+ )
339
+ }
340
+
341
+ export default SyllabusEditor