@learnpack/learnpack 5.0.68 → 5.0.70
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/README.md +13 -13
- package/lib/creatorDist/assets/{index-B01XTAAq.js → index-Chx6V3zd.js} +15989 -15785
- package/{src/creatorDist/assets/index-t6ma_gVm.css → lib/creatorDist/assets/index-Dqo9u2iR.css} +233 -35
- package/lib/creatorDist/index.html +2 -2
- package/lib/creatorDist/rigo-float.gif +0 -0
- package/lib/utils/api.js +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/creator/public/rigo-float.gif +0 -0
- package/src/creator/src/App.tsx +202 -163
- package/src/creator/src/assets/svgs.tsx +41 -1
- package/src/creator/src/components/LessonItem.tsx +10 -3
- package/src/creator/src/components/Message.tsx +1 -1
- package/src/creator/src/components/StepWizard.tsx +32 -18
- package/src/creator/src/components/syllabus/ContentIndex.tsx +202 -0
- package/src/creator/src/components/syllabus/Sidebar.tsx +123 -0
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +134 -0
- package/src/creator/src/index.css +2 -6
- package/src/creator/src/main.tsx +1 -1
- package/src/creator/src/utils/store.ts +13 -4
- package/src/creatorDist/assets/{index-B01XTAAq.js → index-Chx6V3zd.js} +15989 -15785
- package/{lib/creatorDist/assets/index-t6ma_gVm.css → src/creatorDist/assets/index-Dqo9u2iR.css} +233 -35
- package/src/creatorDist/index.html +2 -2
- package/src/creatorDist/rigo-float.gif +0 -0
- package/src/utils/api.ts +2 -2
- package/src/creator/src/components/SyllabusEditor.tsx +0 -300
package/src/creator/src/App.tsx
CHANGED
@@ -1,20 +1,18 @@
|
|
1
|
-
import { useEffect
|
2
|
-
import StepWizard
|
1
|
+
import { useEffect } from "react"
|
2
|
+
import StepWizard from "./components/StepWizard"
|
3
3
|
import SelectableCard from "./components/SelectableCard"
|
4
4
|
import Loader from "./components/Loader"
|
5
|
-
import { SVGS } from "./assets/svgs"
|
6
5
|
import { useNavigate } from "react-router"
|
7
6
|
import Login, { loginWithToken } from "./components/Login"
|
8
7
|
import { useShallow } from "zustand/react/shallow"
|
9
8
|
import useStore from "./utils/store"
|
10
9
|
import { interactiveCreation } from "./utils/rigo"
|
11
10
|
import { checkParams, parseLesson } from "./utils/lib"
|
11
|
+
import FileUploader from "./components/FileUploader"
|
12
12
|
|
13
|
-
//
|
14
|
-
|
15
|
-
|
16
|
-
-Introduction to Machine Learning: Explain What is machine learning and its aplications
|
17
|
-
-What is an AI Model: Explain what is an AI model an its applications`
|
13
|
+
// const exampleContentIndex = `-Introduction to AI: Explain what is AI and its applications
|
14
|
+
// -Introduction to Machine Learning: Explain What is machine learning and its aplications
|
15
|
+
// -What is an AI Model: Explain what is an AI model an its applications`
|
18
16
|
|
19
17
|
function App() {
|
20
18
|
const navigate = useNavigate()
|
@@ -29,157 +27,8 @@ function App() {
|
|
29
27
|
}))
|
30
28
|
)
|
31
29
|
|
32
|
-
// const [currentStep, setCurrentStep] = useState(0)
|
33
|
-
const [steps, setSteps] = useState<Array<Step>>([
|
34
|
-
{
|
35
|
-
title: "Provide a description for your tutorial",
|
36
|
-
slug: "description",
|
37
|
-
content: (
|
38
|
-
<textarea
|
39
|
-
placeholder="Describe your tutorial"
|
40
|
-
className="w-full h-24 border-2 border-gray-300 rounded-md p-2 bg-white"
|
41
|
-
defaultValue={formState.description}
|
42
|
-
onBlur={(e) => {
|
43
|
-
setFormState({
|
44
|
-
description: e.target.value,
|
45
|
-
currentStep: 1,
|
46
|
-
})
|
47
|
-
}}
|
48
|
-
/>
|
49
|
-
),
|
50
|
-
},
|
51
|
-
{
|
52
|
-
title:
|
53
|
-
"First you need to login with 4Geeks.com to use AI Generation tool for creators. ",
|
54
|
-
slug: "login",
|
55
|
-
content: (
|
56
|
-
<Login
|
57
|
-
onFinish={() => {
|
58
|
-
setFormState({
|
59
|
-
currentStep: 2,
|
60
|
-
})
|
61
|
-
}}
|
62
|
-
/>
|
63
|
-
),
|
64
|
-
},
|
65
|
-
{
|
66
|
-
title: "What is the estimated duration for this tutorial?",
|
67
|
-
slug: "duration",
|
68
|
-
content: (
|
69
|
-
<div className="flex flex-row gap-4">
|
70
|
-
<SelectableCard
|
71
|
-
title="Around 30 minutes"
|
72
|
-
// subtitle="This is a tutorial that will take 30 minutes to complete"
|
73
|
-
onClick={() => {
|
74
|
-
setFormState({
|
75
|
-
duration: 30,
|
76
|
-
currentStep: 3,
|
77
|
-
})
|
78
|
-
}}
|
79
|
-
selected={false}
|
80
|
-
/>
|
81
|
-
<SelectableCard
|
82
|
-
title="Around 1 hour"
|
83
|
-
// subtitle="This is a tutorial that will take 1 hour to complete"
|
84
|
-
onClick={() => {
|
85
|
-
setFormState({
|
86
|
-
duration: 60,
|
87
|
-
currentStep: 3,
|
88
|
-
})
|
89
|
-
}}
|
90
|
-
selected={false}
|
91
|
-
/>
|
92
|
-
<SelectableCard
|
93
|
-
title="Around 2 hours"
|
94
|
-
// subtitle="This is a tutorial that will take 2 hours to complete"
|
95
|
-
onClick={() => {
|
96
|
-
setFormState({
|
97
|
-
duration: 120,
|
98
|
-
currentStep: 3,
|
99
|
-
})
|
100
|
-
}}
|
101
|
-
selected={false}
|
102
|
-
/>
|
103
|
-
</div>
|
104
|
-
),
|
105
|
-
},
|
106
|
-
{
|
107
|
-
title: "What is the target audience for this tutorial?",
|
108
|
-
slug: "target-audience",
|
109
|
-
content: (
|
110
|
-
<div className="flex flex-row gap-4">
|
111
|
-
<textarea
|
112
|
-
placeholder="Describe the target audience for this tutorial"
|
113
|
-
className="w-full h-24 border-2 border-gray-300 rounded-md p-2 bg-white"
|
114
|
-
defaultValue={formState.targetAudience}
|
115
|
-
onBlur={(e) => {
|
116
|
-
setFormState({
|
117
|
-
targetAudience: e.target.value,
|
118
|
-
currentStep: 3,
|
119
|
-
})
|
120
|
-
}}
|
121
|
-
/>
|
122
|
-
</div>
|
123
|
-
),
|
124
|
-
},
|
125
|
-
{
|
126
|
-
title: "Do you have a content index for this tutorial?",
|
127
|
-
slug: "content-index",
|
128
|
-
content: (
|
129
|
-
<div className="flex flex-row gap-4 justify-center">
|
130
|
-
<SelectableCard
|
131
|
-
title="Yes"
|
132
|
-
onClick={() => {
|
133
|
-
setFormState({
|
134
|
-
hasContentIndex: true,
|
135
|
-
currentStep: 4,
|
136
|
-
})
|
137
|
-
setSteps([
|
138
|
-
...steps,
|
139
|
-
{
|
140
|
-
title:
|
141
|
-
"Write or paste your content index below, each topic should be defined on a new line, here is an example:",
|
142
|
-
slug: "content-index",
|
143
|
-
content: (
|
144
|
-
<textarea
|
145
|
-
placeholder="Provide a content index for this tutorial"
|
146
|
-
className="w-full h-24 border-2 border-gray-300 rounded-md p-2"
|
147
|
-
defaultValue={exampleContentIndex}
|
148
|
-
onBlur={(e) => {
|
149
|
-
setFormState({
|
150
|
-
contentIndex: e.target.value,
|
151
|
-
isCompleted: true,
|
152
|
-
})
|
153
|
-
}}
|
154
|
-
/>
|
155
|
-
),
|
156
|
-
},
|
157
|
-
])
|
158
|
-
}}
|
159
|
-
selected={false}
|
160
|
-
/>
|
161
|
-
<SelectableCard
|
162
|
-
title="No, help me create one"
|
163
|
-
onClick={() => {
|
164
|
-
setFormState({
|
165
|
-
hasContentIndex: false,
|
166
|
-
isCompleted: true,
|
167
|
-
})
|
168
|
-
|
169
|
-
// createTutorial()
|
170
|
-
// setCurrentStep(4)
|
171
|
-
}}
|
172
|
-
selected={false}
|
173
|
-
/>
|
174
|
-
</div>
|
175
|
-
),
|
176
|
-
},
|
177
|
-
])
|
178
|
-
|
179
30
|
useEffect(() => {
|
180
|
-
console.log(formState, "FORM STATE")
|
181
31
|
if (formState.isCompleted) {
|
182
|
-
// navigate("/syllabus")
|
183
32
|
handleCreateTutorial()
|
184
33
|
}
|
185
34
|
}, [formState])
|
@@ -192,14 +41,29 @@ function App() {
|
|
192
41
|
const { token } = checkParams()
|
193
42
|
if (token) {
|
194
43
|
const user = await loginWithToken(token)
|
195
|
-
console.log(user, "user at the beginning")
|
196
44
|
setAuth({
|
197
45
|
bcToken: token,
|
198
46
|
userId: user.id,
|
199
47
|
rigoToken: user.rigobot.key,
|
200
48
|
})
|
201
|
-
|
202
|
-
|
49
|
+
setFormState({
|
50
|
+
variables: [
|
51
|
+
"description",
|
52
|
+
"duration",
|
53
|
+
"targetAudience",
|
54
|
+
"hasContentIndex",
|
55
|
+
],
|
56
|
+
})
|
57
|
+
} else {
|
58
|
+
setFormState({
|
59
|
+
variables: [
|
60
|
+
"description",
|
61
|
+
"login",
|
62
|
+
"duration",
|
63
|
+
"targetAudience",
|
64
|
+
"hasContentIndex",
|
65
|
+
],
|
66
|
+
})
|
203
67
|
}
|
204
68
|
}
|
205
69
|
|
@@ -226,19 +90,194 @@ function App() {
|
|
226
90
|
hasContentIndex: false,
|
227
91
|
contentIndex: "",
|
228
92
|
isCompleted: false,
|
229
|
-
currentStep:
|
93
|
+
currentStep: "description",
|
230
94
|
})
|
231
95
|
}
|
232
96
|
|
97
|
+
const buildSteps = () => {
|
98
|
+
const steps = [
|
99
|
+
{
|
100
|
+
title: "Provide a description for your tutorial",
|
101
|
+
slug: "description",
|
102
|
+
isCompleted: false,
|
103
|
+
content: (
|
104
|
+
<textarea
|
105
|
+
placeholder="Describe your tutorial"
|
106
|
+
className="w-full h-24 border-2 border-gray-300 rounded-md p-2 bg-white"
|
107
|
+
value={formState.description}
|
108
|
+
onChange={(e) => {
|
109
|
+
setFormState({
|
110
|
+
description: e.target.value,
|
111
|
+
})
|
112
|
+
}}
|
113
|
+
/>
|
114
|
+
),
|
115
|
+
},
|
116
|
+
{
|
117
|
+
title:
|
118
|
+
"First you need to login with 4Geeks.com to use AI Generation tool for creators. ",
|
119
|
+
slug: "login",
|
120
|
+
isCompleted: false,
|
121
|
+
content: (
|
122
|
+
<Login
|
123
|
+
onFinish={() => {
|
124
|
+
setFormState({
|
125
|
+
currentStep: "duration",
|
126
|
+
})
|
127
|
+
}}
|
128
|
+
/>
|
129
|
+
),
|
130
|
+
},
|
131
|
+
{
|
132
|
+
title: "What is the estimated duration for this tutorial?",
|
133
|
+
slug: "duration",
|
134
|
+
isCompleted: false,
|
135
|
+
content: (
|
136
|
+
<div className="flex flex-col md:flex-row gap-2">
|
137
|
+
<SelectableCard
|
138
|
+
title="Around 30 minutes"
|
139
|
+
// subtitle="This is a tutorial that will take 30 minutes to complete"
|
140
|
+
onClick={() => {
|
141
|
+
setFormState({
|
142
|
+
duration: 30,
|
143
|
+
currentStep: "targetAudience",
|
144
|
+
})
|
145
|
+
}}
|
146
|
+
selected={formState.duration === 30}
|
147
|
+
/>
|
148
|
+
<SelectableCard
|
149
|
+
title="Around 1 hour"
|
150
|
+
// subtitle="This is a tutorial that will take 1 hour to complete"
|
151
|
+
onClick={() => {
|
152
|
+
setFormState({
|
153
|
+
duration: 60,
|
154
|
+
currentStep: "targetAudience",
|
155
|
+
})
|
156
|
+
}}
|
157
|
+
selected={formState.duration === 60}
|
158
|
+
/>
|
159
|
+
<SelectableCard
|
160
|
+
title="Around 2 hours"
|
161
|
+
// subtitle="This is a tutorial that will take 2 hours to complete"
|
162
|
+
onClick={() => {
|
163
|
+
setFormState({
|
164
|
+
duration: 120,
|
165
|
+
currentStep: "targetAudience",
|
166
|
+
})
|
167
|
+
}}
|
168
|
+
selected={formState.duration === 120}
|
169
|
+
/>
|
170
|
+
</div>
|
171
|
+
),
|
172
|
+
},
|
173
|
+
{
|
174
|
+
title: "What is the target audience for this tutorial?",
|
175
|
+
slug: "targetAudience",
|
176
|
+
isCompleted: false,
|
177
|
+
content: (
|
178
|
+
<div className="flex flex-row gap-4">
|
179
|
+
<textarea
|
180
|
+
placeholder="Describe the target audience for this tutorial"
|
181
|
+
className="w-full h-24 border-2 border-gray-300 rounded-md p-2 bg-white"
|
182
|
+
defaultValue={formState.targetAudience}
|
183
|
+
onBlur={(e) => {
|
184
|
+
setFormState({
|
185
|
+
targetAudience: e.target.value,
|
186
|
+
})
|
187
|
+
}}
|
188
|
+
/>
|
189
|
+
</div>
|
190
|
+
),
|
191
|
+
},
|
192
|
+
{
|
193
|
+
title: "Do you have a content index for this tutorial?",
|
194
|
+
slug: "hasContentIndex",
|
195
|
+
isCompleted: false,
|
196
|
+
content: (
|
197
|
+
<div className="flex flex-col md:flex-row gap-2 justify-center">
|
198
|
+
<SelectableCard
|
199
|
+
title="Yes"
|
200
|
+
onClick={() => {
|
201
|
+
setFormState({
|
202
|
+
hasContentIndex: true,
|
203
|
+
currentStep: "contentIndex",
|
204
|
+
variables: [...formState.variables, "contentIndex"],
|
205
|
+
})
|
206
|
+
}}
|
207
|
+
selected={false}
|
208
|
+
/>
|
209
|
+
<SelectableCard
|
210
|
+
title="No, help me create one"
|
211
|
+
onClick={() => {
|
212
|
+
setFormState({
|
213
|
+
hasContentIndex: false,
|
214
|
+
isCompleted: true,
|
215
|
+
})
|
216
|
+
}}
|
217
|
+
selected={false}
|
218
|
+
/>
|
219
|
+
</div>
|
220
|
+
),
|
221
|
+
},
|
222
|
+
{
|
223
|
+
title:
|
224
|
+
"Write or paste your content index below, each topic should be defined on a new line, here is an example:",
|
225
|
+
slug: "contentIndex",
|
226
|
+
isCompleted: false,
|
227
|
+
content: (
|
228
|
+
<>
|
229
|
+
<textarea
|
230
|
+
placeholder="Provide a content index for this tutorial"
|
231
|
+
className="w-full h-40 border-2 border-gray-300 rounded-md p-2"
|
232
|
+
value={formState.contentIndex}
|
233
|
+
onChange={(e) => {
|
234
|
+
setFormState({
|
235
|
+
contentIndex: e.target.value,
|
236
|
+
// isCompleted: true,
|
237
|
+
})
|
238
|
+
}}
|
239
|
+
/>
|
240
|
+
<FileUploader
|
241
|
+
onResult={(files) => {
|
242
|
+
// toast.success("File uploaded successfully")
|
243
|
+
let allFilesText = ``
|
244
|
+
files.forEach((file) => {
|
245
|
+
allFilesText += `<FILE NAME="${file.name}">${file.text}</FILE>\n`
|
246
|
+
})
|
247
|
+
setFormState({
|
248
|
+
contentIndex: allFilesText,
|
249
|
+
})
|
250
|
+
}}
|
251
|
+
/>
|
252
|
+
</>
|
253
|
+
),
|
254
|
+
},
|
255
|
+
]
|
256
|
+
|
257
|
+
return steps.filter(
|
258
|
+
(step) =>
|
259
|
+
formState.variables.includes(step.slug) ||
|
260
|
+
step.slug === formState.currentStep
|
261
|
+
)
|
262
|
+
}
|
233
263
|
return (
|
234
264
|
<>
|
235
265
|
{formState.isCompleted ? (
|
236
266
|
<Loader
|
237
267
|
text="Learnpack is setting up your tutorial. It may take a moment..."
|
238
|
-
icon={
|
268
|
+
icon={<img src={"rigo-float.gif"} alt="rigo" className="w-20 h-20" />}
|
239
269
|
/>
|
240
270
|
) : (
|
241
|
-
<StepWizard
|
271
|
+
<StepWizard
|
272
|
+
formState={formState}
|
273
|
+
steps={buildSteps()}
|
274
|
+
setFormState={setFormState}
|
275
|
+
onFinish={() => {
|
276
|
+
setFormState({
|
277
|
+
isCompleted: true,
|
278
|
+
})
|
279
|
+
}}
|
280
|
+
/>
|
242
281
|
)}
|
243
282
|
</>
|
244
283
|
)
|
@@ -196,7 +196,7 @@ export const SVGS = {
|
|
196
196
|
),
|
197
197
|
clip: (
|
198
198
|
<svg
|
199
|
-
fill="
|
199
|
+
fill="var(--four-geeks-blue)"
|
200
200
|
width="20"
|
201
201
|
height="20"
|
202
202
|
viewBox="0 0 32 32"
|
@@ -223,4 +223,44 @@ export const SVGS = {
|
|
223
223
|
/>
|
224
224
|
</svg>
|
225
225
|
),
|
226
|
+
downArrow: (
|
227
|
+
<svg
|
228
|
+
width="7"
|
229
|
+
height="6"
|
230
|
+
viewBox="0 0 7 6"
|
231
|
+
fill="none"
|
232
|
+
xmlns="http://www.w3.org/2000/svg"
|
233
|
+
>
|
234
|
+
<path
|
235
|
+
fillRule="evenodd"
|
236
|
+
clipRule="evenodd"
|
237
|
+
d="M0.100496 1.0705C0.22866 0.950272 0.430019 0.956708 0.550243 1.08487L3.5 4.2294L6.44976 1.08487C6.56998 0.956708 6.77134 0.950272 6.8995 1.0705C7.02767 1.19072 7.0341 1.39208 6.91388 1.52024L3.73206 4.91216C3.67191 4.97628 3.58792 5.01266 3.5 5.01266C3.41208 5.01266 3.32809 4.97628 3.26794 4.91216L0.086122 1.52024C-0.0341029 1.39208 -0.0276674 1.19072 0.100496 1.0705Z"
|
238
|
+
fill="#0084FF"
|
239
|
+
/>
|
240
|
+
</svg>
|
241
|
+
),
|
242
|
+
bottom: (
|
243
|
+
<svg
|
244
|
+
width="12"
|
245
|
+
height="12"
|
246
|
+
viewBox="0 0 24 24"
|
247
|
+
fill="none"
|
248
|
+
xmlns="http://www.w3.org/2000/svg"
|
249
|
+
>
|
250
|
+
<path
|
251
|
+
d="M11.9297 2V22"
|
252
|
+
stroke="#0084FF"
|
253
|
+
strokeWidth="1"
|
254
|
+
strokeLinecap="round"
|
255
|
+
strokeLinejoin="round"
|
256
|
+
/>
|
257
|
+
<path
|
258
|
+
d="M19 16L14 21.1599C13.7437 21.4336 13.434 21.6519 13.0899 21.801C12.7459 21.9502 12.375 22.0271 12 22.0271C11.625 22.0271 11.2541 21.9502 10.9101 21.801C10.566 21.6519 10.2563 21.4336 10 21.1599L5 16"
|
259
|
+
stroke="#0084FF"
|
260
|
+
strokeWidth="1"
|
261
|
+
strokeLinecap="round"
|
262
|
+
strokeLinejoin="round"
|
263
|
+
/>
|
264
|
+
</svg>
|
265
|
+
),
|
226
266
|
}
|
@@ -11,15 +11,22 @@ export interface Lesson {
|
|
11
11
|
|
12
12
|
interface LessonItemProps {
|
13
13
|
lesson: Lesson
|
14
|
-
index: string
|
15
14
|
isNew: boolean
|
16
15
|
onChange: (id: string, newTitle: string) => void
|
17
16
|
onRemove: (id: string) => void
|
18
17
|
}
|
19
18
|
|
19
|
+
function cleanFloatString(input: string): string {
|
20
|
+
const num = parseFloat(input)
|
21
|
+
const isInteger = Number.isInteger(num)
|
22
|
+
|
23
|
+
return isInteger
|
24
|
+
? Math.floor(num).toString().padStart(2, "0")
|
25
|
+
: num.toString()
|
26
|
+
}
|
27
|
+
|
20
28
|
export const LessonItem: React.FC<LessonItemProps> = ({
|
21
29
|
lesson,
|
22
|
-
index,
|
23
30
|
onChange,
|
24
31
|
onRemove,
|
25
32
|
isNew,
|
@@ -32,7 +39,7 @@ export const LessonItem: React.FC<LessonItemProps> = ({
|
|
32
39
|
isNew ? "bg-yellow-50" : ""
|
33
40
|
}`}
|
34
41
|
>
|
35
|
-
<span className="index-circle">{
|
42
|
+
<span className="index-circle">{cleanFloatString(lesson.id)}</span>
|
36
43
|
<span className="text-gray-500 text-sm">
|
37
44
|
{lesson.type[0] + lesson.type.slice(1).toLowerCase()} ●
|
38
45
|
</span>
|
@@ -12,7 +12,7 @@ export const Message: React.FC<TMessage> = ({ type, content }) => {
|
|
12
12
|
|
13
13
|
const isLoading = isAI && !content
|
14
14
|
return isLoading ? (
|
15
|
-
<RigoLoader text="Thinking..." svg={
|
15
|
+
<RigoLoader text="Thinking..." svg={<img src="rigo-float.gif" />} />
|
16
16
|
) : (
|
17
17
|
<div
|
18
18
|
className={`flex items-start space-x-2 p-3 rounded-md border ${
|
@@ -1,45 +1,60 @@
|
|
1
|
-
import React
|
1
|
+
import React from "react"
|
2
2
|
|
3
3
|
export type Step = {
|
4
4
|
title: string
|
5
5
|
subtitle?: string
|
6
6
|
content: React.ReactNode
|
7
7
|
slug: string
|
8
|
+
isCompleted: boolean
|
8
9
|
}
|
9
10
|
|
10
11
|
type Props = {
|
11
12
|
steps: Step[]
|
12
|
-
|
13
|
+
formState: any
|
14
|
+
setFormState: (formState: any) => void
|
15
|
+
onFinish: () => void
|
13
16
|
}
|
14
17
|
|
15
|
-
const StepWizard: React.FC<Props> = ({
|
16
|
-
|
18
|
+
const StepWizard: React.FC<Props> = ({
|
19
|
+
steps,
|
20
|
+
formState,
|
21
|
+
setFormState,
|
22
|
+
onFinish,
|
23
|
+
}) => {
|
24
|
+
const currentStep = formState.currentStep
|
25
|
+
const index = steps.findIndex((step) => step.slug === currentStep)
|
17
26
|
const totalSteps = steps.length
|
18
27
|
|
19
28
|
const goNext = () => {
|
20
|
-
|
29
|
+
const index = steps.findIndex((step) => step.slug === currentStep)
|
30
|
+
if (index < totalSteps - 1)
|
31
|
+
setFormState({
|
32
|
+
...formState,
|
33
|
+
currentStep: steps[index + 1].slug,
|
34
|
+
})
|
21
35
|
}
|
22
36
|
|
23
37
|
const goBack = () => {
|
24
|
-
|
38
|
+
const index = steps.findIndex((step) => step.slug === currentStep)
|
39
|
+
if (index > 0)
|
40
|
+
setFormState({ ...formState, currentStep: steps[index - 1].slug })
|
25
41
|
}
|
26
42
|
|
27
|
-
useEffect(() => {
|
28
|
-
setCurrentStep(initialStep)
|
29
|
-
}, [initialStep])
|
30
|
-
|
31
43
|
return (
|
32
44
|
<div className="min-h-screen flex flex-col items-center justify-center text-center px-4">
|
33
45
|
<div className=" rounded-xl p-8 w-full max-w-xl">
|
34
46
|
<h5 className="text-sm text-blue-400 uppercase mb-2">
|
35
|
-
{steps
|
47
|
+
{steps.find((step) => step.slug === currentStep)?.subtitle ||
|
48
|
+
"Setting up your tutorial"}
|
36
49
|
</h5>
|
37
50
|
<h2 className="text-lg font-medium mb-6">
|
38
|
-
<span className="text-blue-600 mr-1">{
|
39
|
-
{steps
|
51
|
+
<span className="text-blue-600 mr-1">{index + 1}.</span>
|
52
|
+
{steps.find((step) => step.slug === currentStep)?.title}
|
40
53
|
</h2>
|
41
54
|
|
42
|
-
<div className="mb-6">
|
55
|
+
<div className="mb-6">
|
56
|
+
{steps.find((step) => step.slug === currentStep)?.content}
|
57
|
+
</div>
|
43
58
|
|
44
59
|
{/* Dot Indicators */}
|
45
60
|
<div className="flex justify-center mb-4 space-x-2">
|
@@ -47,7 +62,7 @@ const StepWizard: React.FC<Props> = ({ steps, initialStep = 0 }) => {
|
|
47
62
|
<span
|
48
63
|
key={i}
|
49
64
|
className={`h-2 w-2 rounded-full ${
|
50
|
-
i ===
|
65
|
+
i === index ? "bg-blue-600" : "bg-gray-300"
|
51
66
|
}`}
|
52
67
|
/>
|
53
68
|
))}
|
@@ -57,14 +72,13 @@ const StepWizard: React.FC<Props> = ({ steps, initialStep = 0 }) => {
|
|
57
72
|
<div className="flex justify-between">
|
58
73
|
<button
|
59
74
|
onClick={goBack}
|
60
|
-
disabled={
|
75
|
+
disabled={index === 0}
|
61
76
|
className="text-sm text-gray-500 hover:text-gray-900 disabled:opacity-40"
|
62
77
|
>
|
63
78
|
⬅ Back
|
64
79
|
</button>
|
65
80
|
<button
|
66
|
-
onClick={goNext}
|
67
|
-
disabled={currentStep === totalSteps - 1}
|
81
|
+
onClick={index === totalSteps - 1 ? onFinish : goNext}
|
68
82
|
className="text-sm text-blue-600 hover:text-blue-800 disabled:opacity-40"
|
69
83
|
>
|
70
84
|
Next ➡
|