mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: implement FormTagInput for learnings and tags in course creation & edit forms.
This commit is contained in:
parent
000f1031e7
commit
cdd05f6476
5 changed files with 121 additions and 40 deletions
|
|
@ -30,7 +30,7 @@ const CourseClient = (props: any) => {
|
|||
|
||||
function getLearningTags() {
|
||||
// create array of learnings from a string object (comma separated)
|
||||
let learnings = course?.learnings ? course?.learnings.split(',') : []
|
||||
let learnings = course?.learnings ? course?.learnings.split('|') : []
|
||||
setLearnings(learnings)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import * as Form from '@radix-ui/react-form';
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import ThumbnailUpdate from './ThumbnailUpdate';
|
||||
import { useCourse, useCourseDispatch } from '@components/Contexts/CourseContext';
|
||||
import FormTagInput from '@components/Objects/StyledElements/Form/TagInput';
|
||||
|
||||
type EditCourseStructureProps = {
|
||||
orgslug: string
|
||||
|
|
@ -138,24 +139,22 @@ function EditCourseGeneral(props: EditCourseStructureProps) {
|
|||
<FormField name="learnings">
|
||||
<FormLabelAndMessage label="Learnings" message={formik.errors.learnings} />
|
||||
<Form.Control asChild>
|
||||
<Textarea
|
||||
style={{ backgroundColor: 'white' }}
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.learnings}
|
||||
required
|
||||
/>
|
||||
<FormTagInput
|
||||
placeholder="Enter to add..."
|
||||
onChange={(value) => formik.setFieldValue('learnings', value)}
|
||||
value={formik.values.learnings}
|
||||
/>
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
<FormField name="tags">
|
||||
<FormLabelAndMessage label="Tags" message={formik.errors.tags} />
|
||||
<Form.Control asChild>
|
||||
<Textarea
|
||||
style={{ backgroundColor: 'white' }}
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.tags}
|
||||
required
|
||||
/>
|
||||
<FormTagInput
|
||||
placeholder="Enter to add..."
|
||||
onChange={(value) => formik.setFieldValue('tags', value)}
|
||||
value={formik.values.tags}
|
||||
/>
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { useFormik } from 'formik'
|
|||
import * as Yup from 'yup'
|
||||
import { UploadCloud, Image as ImageIcon } from 'lucide-react'
|
||||
import UnsplashImagePicker from "@components/Dashboard/Pages/Course/EditCourseGeneral/UnsplashImagePicker"
|
||||
import FormTagInput from "@components/Objects/StyledElements/Form/TagInput"
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
name: Yup.string()
|
||||
|
|
@ -58,6 +59,7 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
|
|||
{
|
||||
name: values.name,
|
||||
description: values.description,
|
||||
learnings: values.learnings,
|
||||
tags: values.tags,
|
||||
visibility: values.visibility
|
||||
},
|
||||
|
|
@ -200,19 +202,31 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
|
|||
</div>
|
||||
</FormField>
|
||||
|
||||
<FormField name="tags">
|
||||
<FormLabelAndMessage
|
||||
label="Course Tags"
|
||||
message={formik.errors.tags}
|
||||
/>
|
||||
<Form.Control asChild>
|
||||
<Textarea
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.tags}
|
||||
placeholder="Enter tags separated by commas"
|
||||
/>
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
<FormField name="learnings">
|
||||
<FormLabelAndMessage
|
||||
label="Course Learnings (What will you teach?)"
|
||||
message={formik.errors.learnings}
|
||||
/>
|
||||
<FormTagInput
|
||||
placeholder="Enter to add..."
|
||||
value={formik.values.learnings}
|
||||
onChange={(value) => formik.setFieldValue('learnings', value)}
|
||||
error={formik.errors.learnings}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<FormField name="tags">
|
||||
<FormLabelAndMessage
|
||||
label="Course Tags"
|
||||
message={formik.errors.tags}
|
||||
/>
|
||||
<FormTagInput
|
||||
placeholder="Enter to add..."
|
||||
value={formik.values.tags}
|
||||
onChange={(value) => formik.setFieldValue('tags', value)}
|
||||
error={formik.errors.tags}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<FormField name="visibility">
|
||||
<FormLabelAndMessage
|
||||
|
|
|
|||
68
apps/web/components/Objects/StyledElements/Form/TagInput.tsx
Normal file
68
apps/web/components/Objects/StyledElements/Form/TagInput.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import React, { useState, Dispatch, SetStateAction } from 'react'
|
||||
import { Tag, TagInput } from 'emblor'
|
||||
|
||||
interface FormTagInputProps {
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
separator?: string
|
||||
error?: string
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
const FormTagInput = ({
|
||||
value,
|
||||
onChange,
|
||||
separator = '|',
|
||||
error,
|
||||
placeholder,
|
||||
}: FormTagInputProps) => {
|
||||
const initialTags = value
|
||||
? value.split(separator).map((text, i) => ({
|
||||
id: i.toString(),
|
||||
text: text.trim(),
|
||||
}))
|
||||
: []
|
||||
|
||||
const [tags, setTags] = useState<Tag[]>(initialTags)
|
||||
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null)
|
||||
|
||||
const handleTagsChange: Dispatch<SetStateAction<Tag[]>> = (
|
||||
newTagsOrUpdater
|
||||
) => {
|
||||
const newTags =
|
||||
typeof newTagsOrUpdater === 'function'
|
||||
? newTagsOrUpdater(tags)
|
||||
: newTagsOrUpdater
|
||||
|
||||
setTags(newTags)
|
||||
onChange(newTags.map((tag) => tag.text).join(separator))
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="space-y-2">
|
||||
<TagInput
|
||||
tags={tags}
|
||||
setTags={handleTagsChange}
|
||||
placeholder={placeholder}
|
||||
styleClasses={{
|
||||
inlineTagsContainer:
|
||||
'border-input rounded-lg bg-background shadow-xs transition-shadow focus-within:border-ring/40 focus-within:outline-hidden focus-within:ring-[3px] ring-ring/8 dark:ring-ring/12 p-1 gap-1',
|
||||
input:
|
||||
'w-full min-w-[80px] focus-visible:outline-hidden shadow-none px-2 h-7',
|
||||
tag: {
|
||||
body: 'h-7 relative bg-background border border-input hover:bg-background rounded-md font-medium text-xs ps-2 pe-7',
|
||||
closeButton:
|
||||
'absolute -inset-y-px -end-px p-0 rounded-e-lg flex size-7 transition-colors outline-hidden focus-visible:ring-2 focus-visible:ring-ring/30 dark:focus-visible:ring-ring/40 text-muted-foreground/80 hover:text-foreground',
|
||||
},
|
||||
}}
|
||||
activeTagIndex={activeTagIndex}
|
||||
setActiveTagIndex={setActiveTagIndex}
|
||||
/>
|
||||
{error && <p className="text-sm font-medium text-destructive">{error}</p>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FormTagInput
|
||||
|
|
@ -102,7 +102,7 @@ export async function createNewCourse(
|
|||
formData.append('name', course_body.name)
|
||||
formData.append('description', course_body.description)
|
||||
formData.append('public', course_body.visibility)
|
||||
formData.append('learnings', course_body.tags)
|
||||
formData.append('learnings', course_body.learnings)
|
||||
formData.append('tags', course_body.tags)
|
||||
formData.append('about', course_body.description)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue