@learnpack/learnpack 5.0.152 → 5.0.156

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.
@@ -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-l0lFNoeD.js"></script>
14
- <link rel="stylesheet" crossorigin href="/creator/assets/index-CztA582_.css">
13
+ <script type="module" crossorigin src="/creator/assets/index-Df4pwBvU.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/creator/assets/index-C_YTggyk.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -1 +1 @@
1
- {"version":"5.0.152","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.156","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.152",
4
+ "version": "5.0.156",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -26,6 +26,7 @@ function App() {
26
26
  push,
27
27
  cleanHistory,
28
28
  setPlanToRedirect,
29
+ uploadedFiles,
29
30
  } = useStore(
30
31
  useShallow((state) => ({
31
32
  formState: state.formState,
@@ -34,6 +35,7 @@ function App() {
34
35
  push: state.push,
35
36
  cleanHistory: state.cleanHistory,
36
37
  setPlanToRedirect: state.setPlanToRedirect,
38
+ uploadedFiles: state.uploadedFiles,
37
39
  }))
38
40
  )
39
41
 
@@ -58,24 +60,6 @@ function App() {
58
60
  rigoToken: user.rigobot.key,
59
61
  user: user,
60
62
  })
61
- setFormState({
62
- variables: [
63
- "description",
64
- "duration",
65
- "targetAudience",
66
- "hasContentIndex",
67
- ],
68
- })
69
- } else {
70
- setFormState({
71
- variables: [
72
- "description",
73
- "login",
74
- "duration",
75
- "targetAudience",
76
- "hasContentIndex",
77
- ],
78
- })
79
63
  }
80
64
  }
81
65
 
@@ -113,33 +97,50 @@ function App() {
113
97
  }
114
98
 
115
99
  const handleCreateTutorial = async () => {
116
- cleanHistory()
117
- const res = await interactiveCreation({
118
- courseInfo: JSON.stringify(formState),
119
- prevInteractions: "",
120
- })
121
- const lessons = res.parsed.listOfSteps.map((lesson: any) => {
122
- return parseLesson(lesson, [])
123
- })
100
+ try {
101
+ cleanHistory()
124
102
 
125
- push({
126
- lessons,
127
- courseInfo: {
128
- ...formState,
129
- title: res.parsed.title,
130
- description: res.parsed.description,
131
- },
132
- })
133
- navigate("/creator/syllabus")
134
- setFormState({
135
- description: "",
136
- duration: 0,
137
- targetAudience: "",
138
- hasContentIndex: false,
139
- contentIndex: "",
140
- isCompleted: false,
141
- currentStep: "description",
142
- })
103
+ const res = await interactiveCreation({
104
+ courseInfo: `${JSON.stringify(formState)}
105
+ ${
106
+ uploadedFiles.length > 0
107
+ ? `These files where uploaded by the user: \n\n${JSON.stringify(
108
+ uploadedFiles
109
+ )}`
110
+ : ""
111
+ }`,
112
+ prevInteractions: "",
113
+ })
114
+ const lessons = res.parsed.listOfSteps.map((lesson: any) => {
115
+ return parseLesson(lesson, [])
116
+ })
117
+
118
+ push({
119
+ lessons,
120
+ courseInfo: {
121
+ ...formState,
122
+ title: res.parsed.title,
123
+ description: res.parsed.description,
124
+ },
125
+ })
126
+ navigate("/creator/syllabus")
127
+ setFormState({
128
+ description: "",
129
+ duration: 0,
130
+ targetAudience: "",
131
+ hasContentIndex: false,
132
+ contentIndex: "",
133
+ isCompleted: false,
134
+ currentStep: "description",
135
+ })
136
+ } catch (error) {
137
+ console.error(error)
138
+ toast.error("Something went wrong. Please try again.")
139
+ setFormState({
140
+ isCompleted: false,
141
+ currentStep: "hasContentIndex",
142
+ })
143
+ }
143
144
  }
144
145
 
145
146
  const buildSteps = () => {
@@ -167,7 +168,8 @@ function App() {
167
168
  {
168
169
  title: "What is the estimated duration for this tutorial?",
169
170
  slug: "duration",
170
- isCompleted: false,
171
+ isCompleted: formState.duration > 0,
172
+ required: true,
171
173
  content: (
172
174
  <div className="flex flex-col md:flex-row gap-2">
173
175
  <SelectableCard
@@ -214,24 +216,28 @@ function App() {
214
216
  <>
215
217
  <div className="flex flex-col md:flex-row gap-2 justify-center">
216
218
  <SelectableCard
217
- title="📄 Yes"
219
+ title=" No, help me create one"
218
220
  onClick={() => {
219
221
  setFormState({
220
- hasContentIndex: true,
221
- currentStep: "contentIndex",
222
- variables: [...formState.variables, "contentIndex"],
223
- // variables: [...formState.variables.filter((v) => v !== "hasContentIndex"), "contentIndex"],
222
+ hasContentIndex: false,
223
+ currentStep: "verifyHuman",
224
+ variables: [
225
+ ...formState.variables.filter(
226
+ (v) => v !== "contentIndex"
227
+ ),
228
+ ],
229
+ // isCompleted: true,
224
230
  })
225
231
  }}
226
232
  selected={false}
227
233
  />
228
234
  <SelectableCard
229
- title="🛠️ No, help me create one"
235
+ title=" Yes"
230
236
  onClick={() => {
231
237
  setFormState({
232
- hasContentIndex: false,
233
- currentStep: "verifyHuman",
234
- // isCompleted: true,
238
+ hasContentIndex: true,
239
+ currentStep: "contentIndex",
240
+ variables: [...formState.variables, "contentIndex"],
235
241
  })
236
242
  }}
237
243
  selected={false}
@@ -245,7 +251,9 @@ function App() {
245
251
  slug: "contentIndex",
246
252
  helpText:
247
253
  "It could be just text, paste an URL or even upload a document.",
248
- isCompleted: false,
254
+ isCompleted:
255
+ formState.contentIndex.length > 0 || uploadedFiles.length > 0,
256
+ required: true,
249
257
  content: (
250
258
  <Uploader
251
259
  onFinish={(text) => {
@@ -264,7 +272,7 @@ function App() {
264
272
  isCompleted: false,
265
273
  content: (
266
274
  <TurnstileChallenge
267
- siteKey={"0x4AAAAAABeKMBYYinMU4Ib0"}
275
+ siteKey={"0x4AAAAAABeZ9tjEevGBsJFU"}
268
276
  onSuccess={async (token) => {
269
277
  const _isHuman = await isHuman(token)
270
278
  if (_isHuman) {
@@ -282,12 +290,15 @@ function App() {
282
290
  },
283
291
  ]
284
292
 
293
+ console.log(formState.variables, "FORM STATE VAIRABLEs")
294
+
285
295
  return steps.filter(
286
296
  (step) =>
287
297
  formState.variables.includes(step.slug) ||
288
298
  step.slug === formState.currentStep
289
299
  )
290
300
  }
301
+
291
302
  return (
292
303
  <>
293
304
  <ParamsChecker />
@@ -297,18 +308,16 @@ function App() {
297
308
  icon={<img src={RIGO_FLOAT_GIT} alt="rigo" className="w-20 h-20" />}
298
309
  />
299
310
  ) : (
300
- <div className="">
301
- <StepWizard
302
- formState={formState}
303
- steps={buildSteps()}
304
- setFormState={setFormState}
305
- onFinish={() => {
306
- setFormState({
307
- isCompleted: true,
308
- })
309
- }}
310
- />
311
- </div>
311
+ <StepWizard
312
+ formState={formState}
313
+ steps={buildSteps()}
314
+ setFormState={setFormState}
315
+ onFinish={() => {
316
+ setFormState({
317
+ isCompleted: true,
318
+ })
319
+ }}
320
+ />
312
321
  )}
313
322
  </>
314
323
  )
@@ -345,4 +345,50 @@ export const SVGS = {
345
345
  />
346
346
  </svg>
347
347
  ),
348
+ google: (
349
+ <svg
350
+ width="20px"
351
+ height="20px"
352
+ viewBox="-0.5 0 48 48"
353
+ version="1.1"
354
+ xmlns="http://www.w3.org/2000/svg"
355
+ xmlnsXlink="http://www.w3.org/1999/xlink"
356
+ >
357
+ <title>Google-color</title>
358
+ <desc>Created with Sketch.</desc>
359
+ <defs></defs>
360
+ <g
361
+ id="Icons"
362
+ stroke="none"
363
+ stroke-width="1"
364
+ fill="none"
365
+ fill-rule="evenodd"
366
+ >
367
+ <g id="Color-" transform="translate(-401.000000, -860.000000)">
368
+ <g id="Google" transform="translate(401.000000, 860.000000)">
369
+ <path
370
+ d="M9.82727273,24 C9.82727273,22.4757333 10.0804318,21.0144 10.5322727,19.6437333 L2.62345455,13.6042667 C1.08206818,16.7338667 0.213636364,20.2602667 0.213636364,24 C0.213636364,27.7365333 1.081,31.2608 2.62025,34.3882667 L10.5247955,28.3370667 C10.0772273,26.9728 9.82727273,25.5168 9.82727273,24"
371
+ id="Fill-1"
372
+ fill="#FBBC05"
373
+ ></path>
374
+ <path
375
+ d="M23.7136364,10.1333333 C27.025,10.1333333 30.0159091,11.3066667 32.3659091,13.2266667 L39.2022727,6.4 C35.0363636,2.77333333 29.6954545,0.533333333 23.7136364,0.533333333 C14.4268636,0.533333333 6.44540909,5.84426667 2.62345455,13.6042667 L10.5322727,19.6437333 C12.3545909,14.112 17.5491591,10.1333333 23.7136364,10.1333333"
376
+ id="Fill-2"
377
+ fill="#EB4335"
378
+ ></path>
379
+ <path
380
+ d="M23.7136364,37.8666667 C17.5491591,37.8666667 12.3545909,33.888 10.5322727,28.3562667 L2.62345455,34.3946667 C6.44540909,42.1557333 14.4268636,47.4666667 23.7136364,47.4666667 C29.4455,47.4666667 34.9177955,45.4314667 39.0249545,41.6181333 L31.5177727,35.8144 C29.3995682,37.1488 26.7323182,37.8666667 23.7136364,37.8666667"
381
+ id="Fill-3"
382
+ fill="#34A853"
383
+ ></path>
384
+ <path
385
+ d="M46.1454545,24 C46.1454545,22.6133333 45.9318182,21.12 45.6113636,19.7333333 L23.7136364,19.7333333 L23.7136364,28.8 L36.3181818,28.8 C35.6879545,31.8912 33.9724545,34.2677333 31.5177727,35.8144 L39.0249545,41.6181333 C43.3393409,37.6138667 46.1454545,31.6490667 46.1454545,24"
386
+ id="Fill-4"
387
+ fill="#4285F4"
388
+ ></path>
389
+ </g>
390
+ </g>
391
+ </g>
392
+ </svg>
393
+ ),
348
394
  }
@@ -4,6 +4,7 @@ import mammoth from "mammoth"
4
4
  import { SVGS } from "../assets/svgs"
5
5
  import pdfWorker from "pdfjs-dist/build/pdf.worker?worker"
6
6
  import { ContentCard } from "./ContentCard"
7
+ import useStore from "../utils/store"
7
8
 
8
9
  pdfjsLib.GlobalWorkerOptions.workerPort = new pdfWorker()
9
10
 
@@ -20,16 +21,16 @@ export interface ParsedFile {
20
21
  }
21
22
 
22
23
  interface FileUploaderProps {
23
- onResult: (files: ParsedFile[]) => void
24
+ // onResult: (files: ParsedFile[]) => void
24
25
  styledAs?: "button" | "card"
25
26
  }
26
27
 
27
- const FileUploader: React.FC<FileUploaderProps> = ({
28
- onResult,
29
- styledAs = "button",
30
- }) => {
28
+ const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
31
29
  const inputRef = useRef<HTMLInputElement>(null)
30
+ const uploadedFiles = useStore((state) => state.uploadedFiles)
31
+ const setUploadedFiles = useStore((state) => state.setUploadedFiles)
32
32
  const [isDragging, setIsDragging] = useState(false)
33
+ // const [parsedFiles, setParsedFiles] = useState<ParsedFile[]>([]) F
33
34
 
34
35
  const extractText = async (file: File): Promise<ParsedFile> => {
35
36
  const { type, name } = file
@@ -66,13 +67,12 @@ const FileUploader: React.FC<FileUploaderProps> = ({
66
67
  allowedTypes.includes(file.type)
67
68
  )
68
69
  const parsed = await Promise.all(validFiles.map(extractText))
69
- console.log(parsed, "parsed files")
70
- onResult(parsed)
70
+ setUploadedFiles([...uploadedFiles, ...parsed])
71
71
  }
72
72
 
73
- const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
73
+ const handleInput = async (e: React.ChangeEvent<HTMLInputElement>) => {
74
74
  if (!e.target.files) return
75
- parseFiles(e.target.files)
75
+ await parseFiles(e.target.files)
76
76
  }
77
77
 
78
78
  const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
@@ -84,14 +84,30 @@ const FileUploader: React.FC<FileUploaderProps> = ({
84
84
  }
85
85
 
86
86
  return (
87
- <>
87
+ <div className="flex flex-col gap-2 w-full">
88
+ {uploadedFiles.length > 0 && styledAs === "card" && (
89
+ <div className="w-full flex flex-row gap-2 flex-wrap justify-center items-center ">
90
+ {uploadedFiles.map((file, idx) => (
91
+ <div
92
+ key={idx}
93
+ className="p-3 rounded-md bg-white shadow-sm text-sm text-gray-800 text-left "
94
+ title={file.name}
95
+ >
96
+ <strong>{file.name.slice(0, 20)}...</strong>
97
+ <button
98
+ className="text-gray-600 mt-1 float-right cursor-pointer"
99
+ onClick={() =>
100
+ setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx))
101
+ }
102
+ >
103
+ {SVGS.trash}
104
+ </button>
105
+ </div>
106
+ ))}
107
+ </div>
108
+ )}
88
109
  {styledAs === "button" && (
89
- <div
90
- className="flex items-center justify-center"
91
- onDragOver={() => setIsDragging(true)}
92
- onDragLeave={() => setIsDragging(false)}
93
- onDrop={handleDrop}
94
- >
110
+ <div className="flex items-center justify-end gap-2 w-100">
95
111
  <button
96
112
  type="button"
97
113
  className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
@@ -101,22 +117,28 @@ const FileUploader: React.FC<FileUploaderProps> = ({
101
117
  </button>
102
118
  </div>
103
119
  )}
120
+
104
121
  {styledAs === "card" && (
105
- <ContentCard
106
- description={
107
- isDragging ? "Drop it here" : "Upload a PDF or drag it here"
108
- }
109
- icon={isDragging ? SVGS.clip : SVGS.pdf}
110
- onClick={() => inputRef.current?.click()}
111
- onDragOver={(e) => {
112
- e.preventDefault()
113
- setIsDragging(true)
114
- }}
115
- onDragLeave={() => setIsDragging(false)}
116
- onDrop={handleDrop}
117
- className={isDragging ? "border-blue-600 bg-blue-50" : ""}
118
- />
122
+ <>
123
+ <ContentCard
124
+ description={
125
+ isDragging
126
+ ? "Drop it here"
127
+ : "Upload a PDF or DOCX file or drag it here"
128
+ }
129
+ icon={isDragging ? SVGS.clip : SVGS.pdf}
130
+ onClick={() => inputRef.current?.click()}
131
+ onDragOver={(e) => {
132
+ e.preventDefault()
133
+ setIsDragging(true)
134
+ }}
135
+ onDragLeave={() => setIsDragging(false)}
136
+ onDrop={handleDrop}
137
+ className={isDragging ? "border-blue-600 bg-blue-50" : ""}
138
+ />
139
+ </>
119
140
  )}
141
+
120
142
  <input
121
143
  ref={inputRef}
122
144
  type="file"
@@ -125,7 +147,7 @@ const FileUploader: React.FC<FileUploaderProps> = ({
125
147
  onChange={handleInput}
126
148
  style={{ display: "none" }}
127
149
  />
128
- </>
150
+ </div>
129
151
  )
130
152
  }
131
153
 
@@ -59,6 +59,11 @@ export default function Login({ onFinish }: { onFinish: () => void }) {
59
59
  window.location.href = `${BREATHECODE_HOST}/v1/auth/github/?url=${url}`
60
60
  }
61
61
 
62
+ const redirectGoogle = () => {
63
+ const url = stringToBase64(getCurrentUrlWithQueryParams())
64
+ window.location.href = `${BREATHECODE_HOST}/v1/auth/google?url=${url}`
65
+ }
66
+
62
67
  return (
63
68
  <div
64
69
  className="fixed inset-0 bg-black/50 flex items-center justify-center z-1000"
@@ -78,6 +83,12 @@ export default function Login({ onFinish }: { onFinish: () => void }) {
78
83
  >
79
84
  {SVGS.github} LOGIN WITH GITHUB
80
85
  </button>
86
+ <button
87
+ onClick={redirectGoogle}
88
+ className="w-full border border-gray-300 py-2 rounded-md font-semibold flex items-center justify-center gap-2 mb-4 cursor-pointer"
89
+ >
90
+ {SVGS.google} LOGIN WITH GOOGLE
91
+ </button>
81
92
 
82
93
  <div className="flex items-center mb-4">
83
94
  <hr className="flex-grow border-gray-300" />
@@ -34,10 +34,10 @@ const PreviewGenerator: React.FC = () => {
34
34
  html2canvas(previewElement, {
35
35
  useCORS: true,
36
36
  }).then(async (canvas) => {
37
- const anchor = document.createElement("a")
38
- anchor.href = canvas.toDataURL("image/png")
39
- anchor.download = "preview.png"
40
- anchor.click()
37
+ // const anchor = document.createElement("a")
38
+ // anchor.href = canvas.toDataURL("image/png")
39
+ // anchor.download = "preview.png"
40
+ // anchor.click()
41
41
 
42
42
  const imageUrl = canvas.toDataURL("image/png")
43
43
 
@@ -1,6 +1,6 @@
1
1
  import React from "react"
2
2
  import { ParsedLink } from "./LinkUploader"
3
- import useStore from "../utils/store"
3
+ // import useStore from "../utils/store"
4
4
  import { SVGS } from "../assets/svgs"
5
5
 
6
6
  interface SourceProps {
@@ -14,8 +14,8 @@ interface SourceProps {
14
14
  // }
15
15
 
16
16
  const Source: React.FC<SourceProps> = ({ source }) => {
17
- const setFormState = useStore((state) => state.setFormState)
18
- const formState = useStore((state) => state.formState)
17
+ // const setFormState = useStore((state) => state.setFormState)
18
+ // const formState = useStore((state) => state.formState)
19
19
 
20
20
  const {
21
21
  url,
@@ -28,18 +28,16 @@ const Source: React.FC<SourceProps> = ({ source }) => {
28
28
  // text,
29
29
  } = source
30
30
 
31
-
32
-
33
31
  return (
34
32
  <div className="relative max-w-xs bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow">
35
33
  <div className="p-4 flex flex-col space-y-2">
36
34
  <button
37
35
  className="absolute top-2 right-2"
38
- onClick={() => {
39
- setFormState({
40
- sources: formState.sources.filter((s) => s !== source),
41
- })
42
- }}
36
+ // onClick={() => {
37
+ // setFormState({
38
+ // sources: formState.sources.filter((s) => s !== source),
39
+ // })
40
+ // }}
43
41
  >
44
42
  {SVGS.redClose}
45
43
  </button>
@@ -31,7 +31,7 @@ const StepWizard: React.FC<Props> = ({
31
31
 
32
32
  const goNext = () => {
33
33
  const index = steps.findIndex((step) => step.slug === currentStep)
34
- if (steps[index].required && !formState[steps[index].slug]) {
34
+ if (steps[index].required && !steps[index].isCompleted) {
35
35
  toast.error("Please fill out all required fields!")
36
36
  return
37
37
  }
@@ -48,6 +48,8 @@ const StepWizard: React.FC<Props> = ({
48
48
  setFormState({ ...formState, currentStep: steps[index - 1].slug })
49
49
  }
50
50
 
51
+ console.log(index, totalSteps, steps)
52
+
51
53
  return (
52
54
  <div className="min-h-screen flex flex-col items-center justify-center text-center px-4">
53
55
  <div className=" rounded-xl p-8 w-full max-w-xl">
@@ -87,22 +89,23 @@ const StepWizard: React.FC<Props> = ({
87
89
  {steps.find((step) => step.slug === currentStep)?.content}
88
90
  </div>
89
91
 
90
- {/* Dot Indicators */}
91
-
92
- {/* Navigation */}
93
92
  <div className="flex justify-between">
94
93
  <button
95
94
  onClick={goBack}
96
95
  disabled={index === 0}
97
- className="text-sm text-gray-500 hover:text-gray-900 disabled:opacity-40"
96
+ className={`text-sm text-gray-500 hover:text-gray-900 disabled:opacity-40 ${
97
+ index === 0 ? "cursor-not-allowed" : "cursor-pointer"
98
+ }`}
98
99
  >
99
100
  ⬅ Back
100
101
  </button>
101
102
  <button
102
103
  onClick={index === totalSteps - 1 ? onFinish : goNext}
103
- className="text-sm text-blue-600 hover:text-blue-800 disabled:opacity-40"
104
+ className={`text-sm text-blue-600 hover:text-blue-800 cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed p-2 rounded-md ${
105
+ index === totalSteps - 1 ? "bg-blue-600 text-white" : ""
106
+ }`}
104
107
  >
105
- Next ➡
108
+ {index === totalSteps - 1 ? "Finish 🚀" : "Next ➡"}
106
109
  </button>
107
110
  </div>
108
111
  </div>
@@ -45,17 +45,12 @@ export const Uploader = ({
45
45
  icon={SVGS.contentTable}
46
46
  onClick={() => handleSelectOption("text")}
47
47
  />
48
-
49
- <FileUploader
50
- styledAs="card"
51
- onResult={(file) => {
52
- onFinish(
53
- `The following information comes from a PDF file uploaded by the user: ${JSON.stringify(
54
- file
55
- )}`
56
- )
57
- }}
48
+ <ContentCard
49
+ description="Upload files"
50
+ icon={SVGS.pdf}
51
+ onClick={() => handleSelectOption("files")}
58
52
  />
53
+
59
54
  <ContentCard
60
55
  description="Share a Youtube link"
61
56
  icon={SVGS.youtube}
@@ -66,6 +61,8 @@ export const Uploader = ({
66
61
 
67
62
  {selectedOption === "text" && <TextUploader onFinish={onFinish} />}
68
63
 
64
+ {selectedOption === "files" && <FileUploader styledAs="card" />}
65
+
69
66
  {selectedOption === "youtube" && (
70
67
  <LinkUploader
71
68
  onResult={(link) => {