@learnpack/learnpack 5.0.287 → 5.0.290
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.
- package/lib/commands/serve.js +49 -73
- package/lib/creatorDist/assets/{index-CQMtxRqZ.js → index-7zTdUX04.js} +4797 -4828
- package/lib/creatorDist/index.html +1 -1
- package/lib/utils/export/index.d.ts +1 -0
- package/lib/utils/export/index.js +3 -1
- package/lib/utils/export/types.d.ts +1 -1
- package/lib/utils/export/zip.d.ts +2 -0
- package/lib/utils/export/zip.js +46 -0
- package/package.json +1 -1
- package/src/commands/serve.ts +28 -54
- package/src/creator/src/App.tsx +61 -67
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +1 -21
- package/src/creator/src/utils/lib.ts +468 -477
- package/src/creator/src/utils/store.ts +222 -223
- package/src/creatorDist/assets/{index-CQMtxRqZ.js → index-7zTdUX04.js} +4797 -4828
- package/src/creatorDist/index.html +1 -1
- package/src/utils/export/index.ts +1 -0
- package/src/utils/export/types.ts +1 -1
- package/src/utils/export/zip.ts +55 -0
- package/src/creator/src/components/PassphraseValidator.tsx +0 -47
@@ -10,7 +10,7 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-7zTdUX04.js"></script>
|
14
14
|
<link rel="stylesheet" crossorigin href="/creator/assets/index-C39zeF3W.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
@@ -1,7 +1,9 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.exportToEpub = exports.exportToScorm = void 0;
|
3
|
+
exports.exportToZip = exports.exportToEpub = exports.exportToScorm = void 0;
|
4
4
|
var scorm_1 = require("./scorm");
|
5
5
|
Object.defineProperty(exports, "exportToScorm", { enumerable: true, get: function () { return scorm_1.exportToScorm; } });
|
6
6
|
var epub_1 = require("./epub");
|
7
7
|
Object.defineProperty(exports, "exportToEpub", { enumerable: true, get: function () { return epub_1.exportToEpub; } });
|
8
|
+
var zip_1 = require("./zip");
|
9
|
+
Object.defineProperty(exports, "exportToZip", { enumerable: true, get: function () { return zip_1.exportToZip; } });
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.exportToZip = exportToZip;
|
4
|
+
const path = require("path");
|
5
|
+
const fs = require("fs");
|
6
|
+
const archiver = require("archiver");
|
7
|
+
const mkdirp = require("mkdirp");
|
8
|
+
const rimraf = require("rimraf");
|
9
|
+
const uuid_1 = require("uuid");
|
10
|
+
const shared_1 = require("./shared");
|
11
|
+
async function exportToZip(options) {
|
12
|
+
const { courseSlug, bucket, outDir } = options;
|
13
|
+
// 1. Create temporary folder
|
14
|
+
const tmpName = (0, uuid_1.v4)();
|
15
|
+
const zipOutDir = path.join(outDir, tmpName);
|
16
|
+
rimraf.sync(zipOutDir);
|
17
|
+
mkdirp.sync(zipOutDir);
|
18
|
+
// 2. Download all course files from bucket to temporary directory
|
19
|
+
await (0, shared_1.downloadS3Folder)(bucket, `courses/${courseSlug}/`, zipOutDir);
|
20
|
+
// 3. Create ZIP file
|
21
|
+
const zipName = `${courseSlug}.zip`;
|
22
|
+
const zipPath = path.join(outDir, zipName);
|
23
|
+
// Remove existing zip file if it exists
|
24
|
+
if (fs.existsSync(zipPath)) {
|
25
|
+
fs.unlinkSync(zipPath);
|
26
|
+
}
|
27
|
+
const output = fs.createWriteStream(zipPath);
|
28
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
29
|
+
return new Promise((resolve, reject) => {
|
30
|
+
output.on("close", () => {
|
31
|
+
console.log(`✅ ZIP export completed: ${archive.pointer()} total bytes`);
|
32
|
+
// Clean up temporary directory
|
33
|
+
rimraf.sync(zipOutDir);
|
34
|
+
resolve(zipPath);
|
35
|
+
});
|
36
|
+
archive.on("error", (err) => {
|
37
|
+
console.error("❌ ZIP creation error:", err);
|
38
|
+
rimraf.sync(zipOutDir);
|
39
|
+
reject(err);
|
40
|
+
});
|
41
|
+
archive.pipe(output);
|
42
|
+
// Add all files from the temporary directory to the ZIP
|
43
|
+
archive.directory(zipOutDir, false);
|
44
|
+
archive.finalize();
|
45
|
+
});
|
46
|
+
}
|
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.
|
4
|
+
"version": "5.0.290",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
@@ -56,7 +56,7 @@ import { checkReadability, slugify } from "../utils/creatorUtilities"
|
|
56
56
|
import { checkAndFixSidebarPure } from "../utils/sidebarGenerator"
|
57
57
|
import { handleAssetCreation } from "./publish"
|
58
58
|
import { FormState, Lesson, Syllabus } from "../models/creator"
|
59
|
-
import { exportToScorm, exportToEpub } from "../utils/export"
|
59
|
+
import { exportToScorm, exportToEpub, exportToZip } from "../utils/export"
|
60
60
|
|
61
61
|
const frontMatter = require("front-matter")
|
62
62
|
|
@@ -698,6 +698,7 @@ export default class ServeCommand extends SessionCommand {
|
|
698
698
|
}
|
699
699
|
)
|
700
700
|
|
701
|
+
// TODO: Check if this command is being used
|
701
702
|
app.post("/actions/generate-image/:courseSlug", async (req, res) => {
|
702
703
|
const rigoToken = req.header("x-rigo-token")
|
703
704
|
const { courseSlug } = req.params
|
@@ -1039,8 +1040,6 @@ export default class ServeCommand extends SessionCommand {
|
|
1039
1040
|
const courseSlug = req.query.slug
|
1040
1041
|
const lang = req.query.lang || "en"
|
1041
1042
|
|
1042
|
-
console.log("LANG", lang)
|
1043
|
-
|
1044
1043
|
if (!courseSlug) {
|
1045
1044
|
return res.status(400).json({ error: "Missing courseSlug" })
|
1046
1045
|
}
|
@@ -1574,53 +1573,6 @@ export default class ServeCommand extends SessionCommand {
|
|
1574
1573
|
}
|
1575
1574
|
})
|
1576
1575
|
|
1577
|
-
// app.post("/actions/continue-course/:courseSlug", async (req, res) => {
|
1578
|
-
// console.log("POST /actions/continue-course/:courseSlug")
|
1579
|
-
// const { courseSlug } = req.params
|
1580
|
-
|
1581
|
-
// const { feedback }: { feedback: string } = req.body
|
1582
|
-
|
1583
|
-
// const rigoToken = req.header("x-rigo-token")
|
1584
|
-
// const bcToken = req.header("x-breathecode-token")
|
1585
|
-
// if (!rigoToken || !bcToken) {
|
1586
|
-
// return res.status(400).json({ error: "Missing tokens" })
|
1587
|
-
// }
|
1588
|
-
|
1589
|
-
// const syllabus = await bucket.file(
|
1590
|
-
// `courses/${courseSlug}/.learn/initialSyllabus.json`
|
1591
|
-
// )
|
1592
|
-
// const [content] = await syllabus.download()
|
1593
|
-
// const syllabusJson: Syllabus = JSON.parse(content.toString())
|
1594
|
-
// const notGeneratedLessons = syllabusJson.lessons.filter(
|
1595
|
-
// lesson => !lesson.generated
|
1596
|
-
// )
|
1597
|
-
|
1598
|
-
// const lastGeneratedLesson = findLast(
|
1599
|
-
// syllabusJson.lessons,
|
1600
|
-
// lesson => lesson.generated ?? false
|
1601
|
-
// )
|
1602
|
-
|
1603
|
-
// console.log("ABout to generate", notGeneratedLessons.length, "lessons")
|
1604
|
-
|
1605
|
-
// const firstLessonToGenerate = notGeneratedLessons[0]
|
1606
|
-
|
1607
|
-
// const completionId = await startExerciseGeneration(
|
1608
|
-
// rigoToken,
|
1609
|
-
// syllabusJson.lessons,
|
1610
|
-
// syllabusJson.courseInfo,
|
1611
|
-
// firstLessonToGenerate,
|
1612
|
-
// courseSlug,
|
1613
|
-
// syllabusJson.courseInfo.purpose,
|
1614
|
-
// JSON.stringify(lastGeneratedLesson) +
|
1615
|
-
// `\n\nThe user provided this feedback in relation to the course: ${feedback}`
|
1616
|
-
// )
|
1617
|
-
|
1618
|
-
// return res.json({
|
1619
|
-
// message: "Course continued",
|
1620
|
-
// slug: courseSlug,
|
1621
|
-
// })
|
1622
|
-
// })
|
1623
|
-
|
1624
1576
|
app.get(
|
1625
1577
|
"/courses/:courseSlug/exercises/:exerciseSlug/",
|
1626
1578
|
async (req, res) => {
|
@@ -2048,7 +2000,8 @@ export default class ServeCommand extends SessionCommand {
|
|
2048
2000
|
let outputPath: string
|
2049
2001
|
let filename: string
|
2050
2002
|
|
2051
|
-
|
2003
|
+
switch (format) {
|
2004
|
+
case "scorm": {
|
2052
2005
|
outputPath = await exportToScorm({
|
2053
2006
|
courseSlug: course_slug,
|
2054
2007
|
format: "scorm",
|
@@ -2056,7 +2009,23 @@ export default class ServeCommand extends SessionCommand {
|
|
2056
2009
|
outDir: path.join(__dirname, "../output/directory"),
|
2057
2010
|
})
|
2058
2011
|
filename = `${course_slug}-scorm.zip`
|
2059
|
-
|
2012
|
+
|
2013
|
+
break
|
2014
|
+
}
|
2015
|
+
|
2016
|
+
case "zip": {
|
2017
|
+
outputPath = await exportToZip({
|
2018
|
+
courseSlug: course_slug,
|
2019
|
+
format: "zip",
|
2020
|
+
bucket,
|
2021
|
+
outDir: path.join(__dirname, "../output/directory"),
|
2022
|
+
})
|
2023
|
+
filename = `${course_slug}.zip`
|
2024
|
+
|
2025
|
+
break
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
case "epub": {
|
2060
2029
|
console.log("EPUB export", metadata)
|
2061
2030
|
// Validate required metadata for EPUB
|
2062
2031
|
if (
|
@@ -2085,11 +2054,16 @@ export default class ServeCommand extends SessionCommand {
|
|
2085
2054
|
metadata
|
2086
2055
|
)
|
2087
2056
|
filename = `${course_slug}.epub`
|
2088
|
-
|
2057
|
+
|
2058
|
+
break
|
2059
|
+
}
|
2060
|
+
|
2061
|
+
default: {
|
2089
2062
|
return res.status(400).json({
|
2090
|
-
error: "Invalid format. Supported formats: scorm, epub",
|
2063
|
+
error: "Invalid format. Supported formats: scorm, epub, zip",
|
2091
2064
|
})
|
2092
2065
|
}
|
2066
|
+
}
|
2093
2067
|
|
2094
2068
|
// Send the file and clean up
|
2095
2069
|
res.download(outputPath, filename, err => {
|
package/src/creator/src/App.tsx
CHANGED
@@ -6,7 +6,7 @@ import { useNavigate } from "react-router"
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"
|
7
7
|
import useStore, { TDifficulty } from "./utils/store"
|
8
8
|
|
9
|
-
import { publicInteractiveCreation } from "./utils/rigo"
|
9
|
+
import { publicInteractiveCreation, isHuman } from "./utils/rigo"
|
10
10
|
import {
|
11
11
|
checkParams,
|
12
12
|
isValidRigoToken,
|
@@ -21,8 +21,8 @@ import {
|
|
21
21
|
import { Uploader } from "./components/Uploader"
|
22
22
|
import toast from "react-hot-toast"
|
23
23
|
import { ParamsChecker } from "./components/ParamsChecker"
|
24
|
-
import { RIGO_FLOAT_GIF } from "./utils/constants"
|
25
|
-
|
24
|
+
import { DEV_MODE, RIGO_FLOAT_GIF } from "./utils/constants"
|
25
|
+
import TurnstileChallenge from "./components/TurnstileChallenge"
|
26
26
|
// import TurnstileChallenge from "./components/TurnstileChallenge"
|
27
27
|
import ResumeCourseModal from "./components/ResumeCourseModal"
|
28
28
|
import { possiblePurposes, PurposeSelector } from "./components/PurposeSelector"
|
@@ -31,7 +31,6 @@ import NotificationListener from "./components/NotificationListener"
|
|
31
31
|
import { slugify } from "./utils/creatorUtils"
|
32
32
|
import TurnstileModal from "./components/TurnstileModal"
|
33
33
|
import { TMessage } from "./components/Message"
|
34
|
-
import PassphraseValidator from "./components/PassphraseValidator"
|
35
34
|
|
36
35
|
function App() {
|
37
36
|
const navigate = useNavigate()
|
@@ -86,22 +85,6 @@ function App() {
|
|
86
85
|
checkTechs()
|
87
86
|
}, [])
|
88
87
|
|
89
|
-
const tokenVerification = async () => {
|
90
|
-
const isValid = await isValidPublicToken(auth.publicToken)
|
91
|
-
if (!isValid) {
|
92
|
-
setAuth({
|
93
|
-
...auth,
|
94
|
-
publicToken: ""
|
95
|
-
})
|
96
|
-
}
|
97
|
-
}
|
98
|
-
|
99
|
-
useEffect(() => {
|
100
|
-
if (auth.publicToken) {
|
101
|
-
tokenVerification()
|
102
|
-
}
|
103
|
-
}, [auth])
|
104
|
-
|
105
88
|
const verifyToken = async () => {
|
106
89
|
const { token } = checkParams(["token"])
|
107
90
|
if (token) {
|
@@ -116,29 +99,6 @@ function App() {
|
|
116
99
|
}
|
117
100
|
}
|
118
101
|
|
119
|
-
const getGenerationMode = (): string => {
|
120
|
-
const urlParams = new URLSearchParams(window.location.search);
|
121
|
-
const configParams = urlParams.get('configParams');
|
122
|
-
|
123
|
-
if (!configParams) {
|
124
|
-
return 'next-three';
|
125
|
-
}
|
126
|
-
|
127
|
-
try {
|
128
|
-
const decodedConfig = decodeURIComponent(configParams);
|
129
|
-
const config = JSON.parse(decodedConfig);
|
130
|
-
|
131
|
-
if (config?.page?.generation === 'auto') {
|
132
|
-
return 'continue-with-all';
|
133
|
-
}
|
134
|
-
|
135
|
-
return 'next-three';
|
136
|
-
} catch (error) {
|
137
|
-
console.error('Error parsing configParams:', error);
|
138
|
-
return 'next-three';
|
139
|
-
}
|
140
|
-
};
|
141
|
-
|
142
102
|
const checkQueryParams = () => {
|
143
103
|
const {
|
144
104
|
description,
|
@@ -163,6 +123,7 @@ function App() {
|
|
163
123
|
}
|
164
124
|
|
165
125
|
if (description) {
|
126
|
+
console.log("description", description)
|
166
127
|
setFormState({
|
167
128
|
description: description,
|
168
129
|
})
|
@@ -170,9 +131,12 @@ function App() {
|
|
170
131
|
if (duration && !isNaN(parseInt(duration))) {
|
171
132
|
if (["30", "60", "120"].includes(duration)) {
|
172
133
|
const durationInt = parseInt(duration)
|
134
|
+
console.log("duration", durationInt)
|
173
135
|
setFormState({
|
174
136
|
duration: durationInt,
|
175
137
|
})
|
138
|
+
} else {
|
139
|
+
console.log("Invalid duration received in params", duration)
|
176
140
|
}
|
177
141
|
}
|
178
142
|
|
@@ -238,13 +202,13 @@ function App() {
|
|
238
202
|
}
|
239
203
|
}
|
240
204
|
|
241
|
-
if (auth.publicToken) {
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
205
|
+
if (auth.publicToken && !isAuthenticated) {
|
206
|
+
const isPublicTokenValid = await isValidPublicToken(auth.publicToken)
|
207
|
+
if (isPublicTokenValid) {
|
208
|
+
tokenToUse = auth.publicToken
|
209
|
+
isAuthenticated = true
|
210
|
+
tokenType = "public"
|
211
|
+
}
|
248
212
|
}
|
249
213
|
if (!isAuthenticated) {
|
250
214
|
setShowTurnstileModal(true)
|
@@ -331,7 +295,7 @@ function App() {
|
|
331
295
|
onFinish={(purpose) => {
|
332
296
|
setFormState({
|
333
297
|
purpose: purpose,
|
334
|
-
currentStep: "
|
298
|
+
currentStep: "verifyHuman",
|
335
299
|
})
|
336
300
|
}}
|
337
301
|
/>
|
@@ -350,7 +314,7 @@ function App() {
|
|
350
314
|
onClick={() => {
|
351
315
|
setFormState({
|
352
316
|
duration: 30,
|
353
|
-
currentStep: "
|
317
|
+
currentStep: "verifyHuman",
|
354
318
|
})
|
355
319
|
}}
|
356
320
|
selected={formState.duration === 30}
|
@@ -361,7 +325,7 @@ function App() {
|
|
361
325
|
onClick={() => {
|
362
326
|
setFormState({
|
363
327
|
duration: 60,
|
364
|
-
currentStep: "
|
328
|
+
currentStep: "verifyHuman",
|
365
329
|
})
|
366
330
|
}}
|
367
331
|
selected={formState.duration === 60}
|
@@ -372,7 +336,7 @@ function App() {
|
|
372
336
|
onClick={() => {
|
373
337
|
setFormState({
|
374
338
|
duration: 120,
|
375
|
-
currentStep: "
|
339
|
+
currentStep: "verifyHuman",
|
376
340
|
})
|
377
341
|
}}
|
378
342
|
selected={formState.duration === 120}
|
@@ -381,20 +345,52 @@ function App() {
|
|
381
345
|
),
|
382
346
|
},
|
383
347
|
{
|
384
|
-
title: t("stepWizard.
|
385
|
-
slug: "
|
348
|
+
title: t("stepWizard.verifyHuman"),
|
349
|
+
slug: "verifyHuman",
|
386
350
|
isCompleted: false,
|
351
|
+
required: true,
|
387
352
|
content: (
|
388
|
-
|
389
|
-
{
|
390
|
-
|
391
|
-
|
353
|
+
<TurnstileChallenge
|
354
|
+
siteKey={
|
355
|
+
DEV_MODE ? "0x4AAAAAABeKMBYYinMU4Ib0" : "0x4AAAAAABeZ9tjEevGBsJFU"
|
356
|
+
}
|
357
|
+
onSuccess={async (token) => {
|
358
|
+
const { human, message, token: jwtToken } = await isHuman(token)
|
359
|
+
if (human) {
|
360
|
+
toast.success(t("stepWizard.humanSuccess"))
|
361
|
+
|
362
|
+
console.log("JWT TOKEN received", jwtToken)
|
392
363
|
setAuth({
|
393
364
|
...auth,
|
394
|
-
publicToken:
|
365
|
+
publicToken: jwtToken,
|
366
|
+
})
|
367
|
+
setFormState({
|
368
|
+
currentStep: "hasContentIndex",
|
395
369
|
})
|
396
|
-
}
|
397
|
-
|
370
|
+
} else {
|
371
|
+
toast.error(message)
|
372
|
+
setFormState({
|
373
|
+
currentStep: "duration",
|
374
|
+
})
|
375
|
+
}
|
376
|
+
}}
|
377
|
+
onError={() => {
|
378
|
+
toast.error(t("turnstileModal.error"), {
|
379
|
+
duration: 10000,
|
380
|
+
})
|
381
|
+
setFormState({
|
382
|
+
currentStep: "duration",
|
383
|
+
})
|
384
|
+
}}
|
385
|
+
/>
|
386
|
+
),
|
387
|
+
},
|
388
|
+
{
|
389
|
+
title: t("stepWizard.hasContentIndex"),
|
390
|
+
slug: "hasContentIndex",
|
391
|
+
isCompleted: false,
|
392
|
+
content: (
|
393
|
+
<>
|
398
394
|
<div className="flex flex-col md:flex-row gap-2 justify-center">
|
399
395
|
<SelectableCard
|
400
396
|
title={t("stepWizard.hasContentIndexCard.no")}
|
@@ -409,7 +405,7 @@ function App() {
|
|
409
405
|
isCompleted: true,
|
410
406
|
})
|
411
407
|
}}
|
412
|
-
|
408
|
+
// selected={formState.hasContentIndex === false}
|
413
409
|
/>
|
414
410
|
<SelectableCard
|
415
411
|
title={t("stepWizard.hasContentIndexCard.yes")}
|
@@ -420,7 +416,7 @@ function App() {
|
|
420
416
|
variables: [...formState.variables, "contentIndex"],
|
421
417
|
})
|
422
418
|
}}
|
423
|
-
|
419
|
+
// selected={formState.hasContentIndex === true}
|
424
420
|
/>
|
425
421
|
</div>
|
426
422
|
</>
|
@@ -489,11 +485,9 @@ function App() {
|
|
489
485
|
|
490
486
|
push({
|
491
487
|
lessons,
|
492
|
-
generationMode: getGenerationMode() as "next-three" | "continue-with-all",
|
493
488
|
courseInfo: {
|
494
489
|
...formState,
|
495
490
|
title: res.parsed.title,
|
496
|
-
|
497
491
|
slug: slugify(fixTitleLength(res.parsed.title)),
|
498
492
|
description: res.parsed.description,
|
499
493
|
language:
|
@@ -14,7 +14,6 @@ import {
|
|
14
14
|
useConsumableCall,
|
15
15
|
isValidRigoToken,
|
16
16
|
isValidPublicToken,
|
17
|
-
getMyPackages,
|
18
17
|
} from "../../utils/lib"
|
19
18
|
|
20
19
|
import Loader from "../Loader"
|
@@ -75,7 +74,7 @@ const SyllabusEditor: React.FC = () => {
|
|
75
74
|
}, [syllabus, navigate])
|
76
75
|
|
77
76
|
useEffect(() => {
|
78
|
-
;
|
77
|
+
;(async () => {
|
79
78
|
const { token } = checkParams(["token"])
|
80
79
|
if (token) {
|
81
80
|
const user = await loginWithToken(token)
|
@@ -93,25 +92,6 @@ const SyllabusEditor: React.FC = () => {
|
|
93
92
|
checkSlug()
|
94
93
|
}, [])
|
95
94
|
|
96
|
-
|
97
|
-
const checkMyPackages = async () => {
|
98
|
-
if (auth.rigoToken) {
|
99
|
-
const packages = await getMyPackages(auth.rigoToken)
|
100
|
-
if (Array.isArray(packages) && packages.length === 0) {
|
101
|
-
push({
|
102
|
-
...syllabus,
|
103
|
-
generationMode: "continue-with-all",
|
104
|
-
})
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
useEffect(() => {
|
110
|
-
if (auth.rigoToken) {
|
111
|
-
checkMyPackages()
|
112
|
-
}
|
113
|
-
}, [auth])
|
114
|
-
|
115
95
|
const checkSlug = async () => {
|
116
96
|
if (!syllabus.courseInfo.title) {
|
117
97
|
toast.error("Please provide a title for the course")
|