@learnpack/learnpack 5.0.71 → 5.0.75

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 (37) hide show
  1. package/README.md +13 -13
  2. package/lib/commands/publish.js +9 -6
  3. package/lib/commands/serve.js +48 -1
  4. package/lib/creatorDist/assets/{index-k_eF99Sf.css → index-BJ2JJzVC.css} +48 -12
  5. package/lib/creatorDist/assets/{index-Dm2fdeOs.js → index-CKBeex0S.js} +36853 -30578
  6. package/lib/creatorDist/index.html +2 -2
  7. package/lib/utils/api.js +18 -7
  8. package/lib/utils/creatorUtilities.d.ts +3 -0
  9. package/lib/utils/creatorUtilities.js +3 -0
  10. package/oclif.manifest.json +1 -1
  11. package/package.json +1 -1
  12. package/src/commands/init.ts +1 -0
  13. package/src/commands/publish.ts +13 -6
  14. package/src/commands/serve.ts +57 -1
  15. package/src/creator/package-lock.json +49 -0
  16. package/src/creator/package.json +1 -0
  17. package/src/creator/src/App.tsx +27 -21
  18. package/src/creator/src/components/ConsumablesManager.tsx +12 -2
  19. package/src/creator/src/components/LessonItem.tsx +3 -2
  20. package/src/creator/src/components/Loader.tsx +5 -1
  21. package/src/creator/src/components/Login.tsx +46 -135
  22. package/src/creator/src/components/syllabus/ContentIndex.tsx +84 -46
  23. package/src/creator/src/components/syllabus/SyllabusEditor.tsx +55 -12
  24. package/src/creator/src/index.css +15 -0
  25. package/src/creator/src/utils/creatorUtils.ts +33 -3
  26. package/src/creator/src/utils/lib.ts +156 -2
  27. package/src/creator/src/utils/rigo.ts +3 -3
  28. package/src/creator/src/utils/store.ts +0 -1
  29. package/src/creatorDist/assets/{index-k_eF99Sf.css → index-BJ2JJzVC.css} +48 -12
  30. package/src/creatorDist/assets/{index-Dm2fdeOs.js → index-CKBeex0S.js} +36853 -30578
  31. package/src/creatorDist/index.html +2 -2
  32. package/src/ui/_app/app.css +1 -1
  33. package/src/ui/_app/app.js +529 -529
  34. package/src/ui/app.tar.gz +0 -0
  35. package/src/utils/api.ts +25 -7
  36. package/src/utils/creatorUtilities.ts +3 -0
  37. package/src/utils/creds.json +0 -13
@@ -10,8 +10,8 @@
10
10
  />
11
11
 
12
12
  <title>Learnpack Creator: Craft tutorials in seconds!</title>
13
- <script type="module" crossorigin src="/creator/assets/index-Dm2fdeOs.js"></script>
14
- <link rel="stylesheet" crossorigin href="/creator/assets/index-k_eF99Sf.css">
13
+ <script type="module" crossorigin src="/creator/assets/index-CKBeex0S.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/creator/assets/index-BJ2JJzVC.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
package/lib/utils/api.js CHANGED
@@ -7,7 +7,8 @@ const cli_ux_1 = require("cli-ux");
7
7
  const axios_1 = require("axios");
8
8
  const HOST = "https://breathecode.herokuapp.com";
9
9
  exports.RIGOBOT_HOST = "https://rigobot.herokuapp.com";
10
- // const RIGOBOT_HOST = "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
10
+ // export const RIGOBOT_HOST =
11
+ // "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us118.gitpod.io"
11
12
  // eslint-disable-next-line
12
13
  const _fetch = require("node-fetch");
13
14
  const fetch = async (url, options = {}, returnAsJson = true) => {
@@ -280,6 +281,12 @@ const with_crud_asset_roles = new Set([
280
281
  "admin",
281
282
  "student",
282
283
  ]);
284
+ const neededPermissions = [
285
+ "add_asset",
286
+ "change_asset",
287
+ "view_asset",
288
+ "delete_asset",
289
+ ];
283
290
  const listUserAcademies = async (breathecodeToken) => {
284
291
  const url = "https://breathecode.herokuapp.com/v1/auth/user/me";
285
292
  try {
@@ -291,14 +298,18 @@ const listUserAcademies = async (breathecodeToken) => {
291
298
  const data = response.data;
292
299
  const academiesMap = new Map();
293
300
  for (const role of data.roles) {
294
- // Only add academies where the user's role is in the whitelist
295
- if (with_crud_asset_roles.has(role.role)) {
296
- const academy = role.academy;
297
- if (!academiesMap.has(academy.id)) {
298
- academiesMap.set(academy.id, academy);
299
- }
301
+ const academy = role.academy;
302
+ if (!academiesMap.has(academy.id)) {
303
+ academiesMap.set(academy.id, academy);
300
304
  }
301
305
  }
306
+ const permissions = new Set(data.permissions.map((p) => p.codename));
307
+ // Validate if the user has ALL the needed permissions
308
+ const hasAllPermissions = neededPermissions.every(permission => permissions.has(permission));
309
+ if (!hasAllPermissions) {
310
+ // The user does not have all the needed permissions
311
+ return [];
312
+ }
302
313
  return [...academiesMap.values()];
303
314
  }
304
315
  catch (error) {
@@ -47,6 +47,9 @@ export declare const makePackageInfo: (choices: any) => {
47
47
  us: any;
48
48
  };
49
49
  slug: any;
50
+ telemetry: {
51
+ batch: string;
52
+ };
50
53
  };
51
54
  export declare function estimateDuration(listOfSteps: string[]): number;
52
55
  export declare function createFileOnDesktop(fileName: string, content: string): Promise<void>;
@@ -141,6 +141,9 @@ const makePackageInfo = (choices) => {
141
141
  .toLowerCase()
142
142
  .replace(/ /g, "-")
143
143
  .replace(/[^\w-]+/g, ""),
144
+ telemetry: {
145
+ batch: "https://breathecode.herokuapp.com/v1/assignment/me/telemetry",
146
+ },
144
147
  };
145
148
  return packageInfo;
146
149
  };
@@ -1 +1 @@
1
- {"version":"5.0.71","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
1
+ {"version":"5.0.75","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@learnpack/learnpack",
3
3
  "description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
4
- "version": "5.0.71",
4
+ "version": "5.0.75",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -585,6 +585,7 @@ class InitComand extends BaseCommand {
585
585
  path.resolve(__dirname, "../../src/utils/templates/gitignore.txt"),
586
586
  path.join(tutorialDir, ".gitignore")
587
587
  )
588
+
588
589
  fs.writeFileSync(
589
590
  path.join(tutorialDir, "learn.json"),
590
591
  JSON.stringify(packageInfo, null, 2)
@@ -207,7 +207,7 @@ class BuildCommand extends SessionCommand {
207
207
 
208
208
  if (!sessionExists || !isValidBreathecodeToken || !isValidToken) {
209
209
  Console.info(
210
- "Almost there! First you need to login with 4Geeks.com to use AI Generation tool for creators. You can create a new account here: https://4geeks.com/creators"
210
+ "Almost there! First you need to login with 4Geeks.com to use AI Generation tool for creators. You can create a new account here: https://4geeks.com/checkout?plan=4geeks-creator"
211
211
  )
212
212
  try {
213
213
  sessionPayload = await SessionManager.login()
@@ -242,13 +242,19 @@ class BuildCommand extends SessionCommand {
242
242
  }
243
243
 
244
244
  const academies = await api.listUserAcademies(sessionPayload.token)
245
- // // console.log(academies, "academies")
245
+
246
+ if (academies.length === 0) {
247
+ Console.error(
248
+ "It seems you cannot publish tutorials. Make sure you creator subscription is up to date here: https://4geeks.com/profile/subscriptions. If you believe there is an issue you can always contact support@4geeks.com"
249
+ )
250
+ process.exit(1)
251
+ }
252
+
246
253
  const { academy, category } = await selectAcademy(
247
254
  academies,
248
255
  sessionPayload.token
249
256
  )
250
257
 
251
- // Read learn.json to get the slug
252
258
  const learnJsonPath = path.join(process.cwd(), "learn.json")
253
259
  if (!fs.existsSync(learnJsonPath)) {
254
260
  this.error("learn.json not found")
@@ -344,9 +350,10 @@ class BuildCommand extends SessionCommand {
344
350
  learnJson.title.us
345
351
  )
346
352
 
347
- const courseShortName = await generateCourseShortName(rigoToken, {
348
- learnJSON: JSON.stringify(learnJson),
349
- })
353
+ const courseShortName = { answer: "testing-tutorial" }
354
+ // const courseShortName = await generateCourseShortName(rigoToken, {
355
+ // learnJSON: JSON.stringify(learnJson),
356
+ // })
350
357
 
351
358
  manifestPWAContent = manifestPWAContent.replace(
352
359
  "{{course_app_name}}",
@@ -54,7 +54,7 @@ export default class ServeCommand extends SessionCommand {
54
54
  })
55
55
 
56
56
  const bucket = bucketStorage.bucket(
57
- process.env.GCP_BUCKET_NAME || "learnpack-creator"
57
+ process.env.GCP_BUCKET_NAME || "learnpack-packages"
58
58
  )
59
59
 
60
60
  async function listFilesWithPrefix(prefix: string) {
@@ -125,6 +125,40 @@ export default class ServeCommand extends SessionCommand {
125
125
  stream.end(buffer)
126
126
  })
127
127
 
128
+ app.post("/upload-image", express.json(), async (req, res) => {
129
+ const { image_url, destination } = req.body
130
+ if (!image_url || !destination) {
131
+ return res
132
+ .status(400)
133
+ .json({ error: "image_url and destination are required" })
134
+ }
135
+
136
+ try {
137
+ const response = await fetch(image_url)
138
+ if (!response.ok) {
139
+ return res
140
+ .status(400)
141
+ .json({ error: `Failed to download image: ${response.statusText}` })
142
+ }
143
+
144
+ const contentType =
145
+ response.headers.get("content-type") || "application/octet-stream"
146
+ const buffer = await response.arrayBuffer()
147
+
148
+ const file = bucket.file(destination)
149
+ await file.save(Buffer.from(buffer), {
150
+ resumable: false,
151
+ contentType,
152
+ })
153
+
154
+ console.log(`✅ Image uploaded to ${file.name}`)
155
+ res.json({ message: "Image uploaded successfully", path: file.name })
156
+ } catch (error) {
157
+ console.error("❌ upload-image error:", error)
158
+ res.status(500).json({ error: (error as Error).message })
159
+ }
160
+ })
161
+
128
162
  app.get("/create", (req, res) => {
129
163
  console.log("GET /create")
130
164
  res.redirect("/creator/")
@@ -227,6 +261,28 @@ continue
227
261
  res.send({ attributes, body })
228
262
  })
229
263
 
264
+ app.get("/.learn/assets/:file", async (req, res) => {
265
+ console.log("GET /.learn/assets/:file", req.params.file)
266
+ const { file } = req.params
267
+ const courseSlug = req.query.slug
268
+
269
+ if (!courseSlug) {
270
+ return res.status(400).send("Course slug is required")
271
+ }
272
+
273
+ const filePath = `courses/${courseSlug}/.learn/assets/${file}`
274
+ const fileRef = bucket.file(filePath)
275
+ const [exists] = await fileRef.exists()
276
+ if (!exists) {
277
+ return res.status(404).send("File not found")
278
+ }
279
+
280
+ const fileStream = fileRef.createReadStream()
281
+ res.set("Content-Type", "application/octet-stream")
282
+ res.set("Content-Disposition", `attachment; filename="${file}"`)
283
+ fileStream.pipe(res)
284
+ })
285
+
230
286
  app.put(
231
287
  "/exercise/:slug/file/:fileName",
232
288
  express.text(),
@@ -11,6 +11,7 @@
11
11
  "@google-cloud/storage": "^7.16.0",
12
12
  "@tailwindcss/vite": "^4.1.3",
13
13
  "axios": "^1.8.4",
14
+ "framer-motion": "^12.9.2",
14
15
  "front-matter": "^4.0.2",
15
16
  "js-yaml": "^4.1.0",
16
17
  "mammoth": "^1.9.0",
@@ -3012,6 +3013,33 @@
3012
3013
  "url": "https://github.com/sponsors/rawify"
3013
3014
  }
3014
3015
  },
3016
+ "node_modules/framer-motion": {
3017
+ "version": "12.9.2",
3018
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.9.2.tgz",
3019
+ "integrity": "sha512-R0O3Jdqbfwywpm45obP+8sTgafmdEcUoShQTAV+rB5pi+Y1Px/FYL5qLLRe5tPtBdN1J4jos7M+xN2VV2oEAbQ==",
3020
+ "license": "MIT",
3021
+ "dependencies": {
3022
+ "motion-dom": "^12.9.1",
3023
+ "motion-utils": "^12.8.3",
3024
+ "tslib": "^2.4.0"
3025
+ },
3026
+ "peerDependencies": {
3027
+ "@emotion/is-prop-valid": "*",
3028
+ "react": "^18.0.0 || ^19.0.0",
3029
+ "react-dom": "^18.0.0 || ^19.0.0"
3030
+ },
3031
+ "peerDependenciesMeta": {
3032
+ "@emotion/is-prop-valid": {
3033
+ "optional": true
3034
+ },
3035
+ "react": {
3036
+ "optional": true
3037
+ },
3038
+ "react-dom": {
3039
+ "optional": true
3040
+ }
3041
+ }
3042
+ },
3015
3043
  "node_modules/front-matter": {
3016
3044
  "version": "4.0.2",
3017
3045
  "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz",
@@ -3983,6 +4011,21 @@
3983
4011
  "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
3984
4012
  "license": "MIT"
3985
4013
  },
4014
+ "node_modules/motion-dom": {
4015
+ "version": "12.9.1",
4016
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.9.1.tgz",
4017
+ "integrity": "sha512-xqXEwRLDYDTzOgXobSoWtytRtGlf7zdkRfFbrrdP7eojaGQZ5Go4OOKtgnx7uF8sAkfr1ZjMvbCJSCIT2h6fkQ==",
4018
+ "license": "MIT",
4019
+ "dependencies": {
4020
+ "motion-utils": "^12.8.3"
4021
+ }
4022
+ },
4023
+ "node_modules/motion-utils": {
4024
+ "version": "12.8.3",
4025
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.8.3.tgz",
4026
+ "integrity": "sha512-GYVauZEbca8/zOhEiYOY9/uJeedYQld6co/GJFKOy//0c/4lDqk0zB549sBYqqV2iMuX+uHrY1E5zd8A2L+1Lw==",
4027
+ "license": "MIT"
4028
+ },
3986
4029
  "node_modules/ms": {
3987
4030
  "version": "2.1.3",
3988
4031
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -4756,6 +4799,12 @@
4756
4799
  "typescript": ">=4.8.4"
4757
4800
  }
4758
4801
  },
4802
+ "node_modules/tslib": {
4803
+ "version": "2.8.1",
4804
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
4805
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
4806
+ "license": "0BSD"
4807
+ },
4759
4808
  "node_modules/turbo-stream": {
4760
4809
  "version": "2.4.0",
4761
4810
  "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
@@ -13,6 +13,7 @@
13
13
  "@google-cloud/storage": "^7.16.0",
14
14
  "@tailwindcss/vite": "^4.1.3",
15
15
  "axios": "^1.8.4",
16
+ "framer-motion": "^12.9.2",
16
17
  "front-matter": "^4.0.2",
17
18
  "js-yaml": "^4.1.0",
18
19
  "mammoth": "^1.9.0",
@@ -3,11 +3,11 @@ import StepWizard from "./components/StepWizard"
3
3
  import SelectableCard from "./components/SelectableCard"
4
4
  import Loader from "./components/Loader"
5
5
  import { useNavigate } from "react-router"
6
- import Login, { loginWithToken } from "./components/Login"
7
6
  import { useShallow } from "zustand/react/shallow"
8
7
  import useStore from "./utils/store"
8
+
9
9
  import { interactiveCreation } from "./utils/rigo"
10
- import { checkParams, parseLesson } from "./utils/lib"
10
+ import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
11
11
  import FileUploader from "./components/FileUploader"
12
12
 
13
13
  // const exampleContentIndex = `-Introduction to AI: Explain what is AI and its applications
@@ -17,9 +17,9 @@ import FileUploader from "./components/FileUploader"
17
17
  function App() {
18
18
  const navigate = useNavigate()
19
19
 
20
- const { auth, formState, setFormState, setSyllabus, setAuth } = useStore(
20
+ const { formState, setFormState, setSyllabus, setAuth } = useStore(
21
21
  useShallow((state) => ({
22
- auth: state.auth,
22
+ // auth: state.auth,
23
23
  formState: state.formState,
24
24
  setFormState: state.setFormState,
25
25
  setSyllabus: state.setSyllabus,
@@ -69,7 +69,7 @@ function App() {
69
69
  }
70
70
 
71
71
  const handleCreateTutorial = async () => {
72
- const res = await interactiveCreation(auth.rigoToken, {
72
+ const res = await interactiveCreation({
73
73
  courseInfo: JSON.stringify(formState),
74
74
  prevInteractions: "",
75
75
  })
@@ -114,21 +114,21 @@ function App() {
114
114
  />
115
115
  ),
116
116
  },
117
- {
118
- title:
119
- "First you need to login with 4Geeks.com to use AI Generation tool for creators. ",
120
- slug: "login",
121
- isCompleted: false,
122
- content: (
123
- <Login
124
- onFinish={() => {
125
- setFormState({
126
- currentStep: "duration",
127
- })
128
- }}
129
- />
130
- ),
131
- },
117
+ // {
118
+ // title:
119
+ // "First you need to login with 4Geeks.com to use AI Generation tool for creators. ",
120
+ // slug: "login",
121
+ // isCompleted: false,
122
+ // content: (
123
+ // <Login
124
+ // onFinish={() => {
125
+ // setFormState({
126
+ // currentStep: "duration",
127
+ // })
128
+ // }}
129
+ // />
130
+ // ),
131
+ // },
132
132
  {
133
133
  title: "What is the estimated duration for this tutorial?",
134
134
  slug: "duration",
@@ -266,7 +266,13 @@ function App() {
266
266
  {formState.isCompleted ? (
267
267
  <Loader
268
268
  text="Learnpack is setting up your tutorial. It may take a moment..."
269
- icon={<img src={"creator/rigo-float.gif"} alt="rigo" className="w-20 h-20" />}
269
+ icon={
270
+ <img
271
+ src={"rigo-float.gif"}
272
+ alt="rigo"
273
+ className="w-20 h-20"
274
+ />
275
+ }
270
276
  />
271
277
  ) : (
272
278
  <StepWizard
@@ -4,6 +4,7 @@ import useStore from "../utils/store"
4
4
 
5
5
  export const ConsumablesManager = () => {
6
6
  const auth = useStore((state) => state.auth)
7
+ const setAuth = useStore((state) => state.setAuth)
7
8
  const setConsumables = useStore((state) => state.setConsumables)
8
9
 
9
10
  useEffect(() => {
@@ -13,8 +14,17 @@ export const ConsumablesManager = () => {
13
14
  }, [auth])
14
15
 
15
16
  const fetchConsumables = async () => {
16
- const consumables = await getConsumables(auth.bcToken)
17
- setConsumables(parseConsumables(consumables.voids))
17
+ try {
18
+ const consumables = await getConsumables(auth.bcToken)
19
+ setConsumables(parseConsumables(consumables.voids))
20
+ } catch (error) {
21
+ setAuth({
22
+ bcToken: "",
23
+ rigoToken: "",
24
+ userId: "",
25
+ user: null,
26
+ })
27
+ }
18
28
  }
19
29
 
20
30
  return <></>
@@ -35,10 +35,11 @@ export const LessonItem: React.FC<LessonItemProps> = ({
35
35
 
36
36
  return (
37
37
  <div
38
- className={`flex items-center space-x-2 border border-gray-200 rounded-md p-3 ${
39
- isNew ? "bg-yellow-50" : ""
38
+ className={`flex items-center space-x-2 relative rounded-md p-3 ${
39
+ isNew ? "border border-learnpack-blue" : "border border-gray-200"
40
40
  }`}
41
41
  >
42
+ {isNew && <span className="red-ball"></span>}
42
43
  <span className="index-circle">{cleanFloatString(lesson.id)}</span>
43
44
  <span className="text-gray-500 text-sm">
44
45
  {lesson.type[0] + lesson.type.slice(1).toLowerCase()} ●
@@ -6,6 +6,7 @@ interface LoaderProps {
6
6
  icon?: React.ReactNode
7
7
  listeningTo?: string
8
8
  initialBuffer?: string
9
+ minheight?: string
9
10
  }
10
11
 
11
12
  const Loader: React.FC<LoaderProps> = ({
@@ -13,6 +14,7 @@ const Loader: React.FC<LoaderProps> = ({
13
14
  icon,
14
15
  listeningTo,
15
16
  initialBuffer,
17
+ minheight = "min-h-screen",
16
18
  }) => {
17
19
  const [buffer, setBuffer] = useState(initialBuffer || "")
18
20
  const preRef = useRef<HTMLPreElement>(null)
@@ -40,7 +42,9 @@ const Loader: React.FC<LoaderProps> = ({
40
42
  }, [buffer])
41
43
 
42
44
  return (
43
- <div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 text-center space-y-6">
45
+ <div
46
+ className={`flex flex-col items-center justify-center bg-gray-50 text-center space-y-6 ${minheight}`}
47
+ >
44
48
  <div className="text-blue-500 text-4xl animate-pulse">{icon}</div>
45
49
  <p className="text-gray-800 text-lg whitespace-pre-line">{text}</p>
46
50
  {!buffer && (