mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
fix: select issue on EditCourseGeneral
This commit is contained in:
parent
634b25be6b
commit
aabb4d190c
4 changed files with 227 additions and 69 deletions
|
|
@ -0,0 +1,158 @@
|
|||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
|
||||
interface CustomSelectProps {
|
||||
value: string;
|
||||
onValueChange: (value: string) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
interface CustomSelectItemProps {
|
||||
value: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface CustomSelectTriggerProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface CustomSelectContentProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const CustomSelectContext = React.createContext<{
|
||||
isOpen: boolean;
|
||||
setIsOpen: (open: boolean) => void;
|
||||
selectedValue: string;
|
||||
setSelectedValue: (value: string) => void;
|
||||
onValueChange: (value: string) => void;
|
||||
} | null>(null);
|
||||
|
||||
export const CustomSelect: React.FC<CustomSelectProps> = ({
|
||||
value,
|
||||
onValueChange,
|
||||
placeholder,
|
||||
className = '',
|
||||
children
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedValue, setSelectedValue] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedValue(value);
|
||||
}, [value]);
|
||||
|
||||
const handleValueChange = (newValue: string) => {
|
||||
setSelectedValue(newValue);
|
||||
onValueChange(newValue);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<CustomSelectContext.Provider
|
||||
value={{
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
selectedValue,
|
||||
setSelectedValue,
|
||||
onValueChange: handleValueChange
|
||||
}}
|
||||
>
|
||||
<div className={`relative ${className}`}>
|
||||
{children}
|
||||
</div>
|
||||
</CustomSelectContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomSelectTrigger: React.FC<CustomSelectTriggerProps> = ({
|
||||
children,
|
||||
className = ''
|
||||
}) => {
|
||||
const context = React.useContext(CustomSelectContext);
|
||||
if (!context) {
|
||||
throw new Error('CustomSelectTrigger must be used within CustomSelect');
|
||||
}
|
||||
|
||||
const { isOpen, setIsOpen } = context;
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1 ${className}`}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className={`h-4 w-4 opacity-50 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomSelectContent: React.FC<CustomSelectContentProps> = ({
|
||||
children,
|
||||
className = ''
|
||||
}) => {
|
||||
const context = React.useContext(CustomSelectContext);
|
||||
if (!context) {
|
||||
throw new Error('CustomSelectContent must be used within CustomSelect');
|
||||
}
|
||||
|
||||
const { isOpen } = context;
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className={`absolute z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 ${className}`}>
|
||||
<div className="p-1">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomSelectItem: React.FC<CustomSelectItemProps> = ({
|
||||
value,
|
||||
children,
|
||||
className = ''
|
||||
}) => {
|
||||
const context = React.useContext(CustomSelectContext);
|
||||
if (!context) {
|
||||
throw new Error('CustomSelectItem must be used within CustomSelect');
|
||||
}
|
||||
|
||||
const { selectedValue, onValueChange } = context;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground ${className}`}
|
||||
onClick={() => onValueChange(value)}
|
||||
>
|
||||
{children}
|
||||
{selectedValue === value && (
|
||||
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomSelectValue: React.FC<{ children?: React.ReactNode }> = ({
|
||||
children
|
||||
}) => {
|
||||
const context = React.useContext(CustomSelectContext);
|
||||
if (!context) {
|
||||
throw new Error('CustomSelectValue must be used within CustomSelect');
|
||||
}
|
||||
|
||||
const { selectedValue } = context;
|
||||
|
||||
return <span>{children || selectedValue}</span>;
|
||||
};
|
||||
|
|
@ -13,12 +13,12 @@ import { useCourse, useCourseDispatch } from '@components/Contexts/CourseContext
|
|||
import FormTagInput from '@components/Objects/StyledElements/Form/TagInput';
|
||||
import LearningItemsList from './LearningItemsList';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@components/ui/select";
|
||||
CustomSelect,
|
||||
CustomSelectContent,
|
||||
CustomSelectItem,
|
||||
CustomSelectTrigger,
|
||||
CustomSelectValue,
|
||||
} from "./CustomSelect";
|
||||
|
||||
type EditCourseStructureProps = {
|
||||
orgslug: string
|
||||
|
|
@ -245,26 +245,26 @@ function EditCourseGeneral(props: EditCourseStructureProps) {
|
|||
<FormField name="thumbnail_type">
|
||||
<FormLabelAndMessage label="Thumbnail Type" />
|
||||
<Form.Control asChild>
|
||||
<Select
|
||||
<CustomSelect
|
||||
value={formik.values.thumbnail_type}
|
||||
onValueChange={(value) => {
|
||||
if (!value) return;
|
||||
formik.setFieldValue('thumbnail_type', value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full bg-white">
|
||||
<SelectValue>
|
||||
<CustomSelectTrigger className="w-full bg-white">
|
||||
<CustomSelectValue>
|
||||
{formik.values.thumbnail_type === 'image' ? 'Image' :
|
||||
formik.values.thumbnail_type === 'video' ? 'Video' :
|
||||
formik.values.thumbnail_type === 'both' ? 'Both' : 'Image'}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="image">Image</SelectItem>
|
||||
<SelectItem value="video">Video</SelectItem>
|
||||
<SelectItem value="both">Both</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</CustomSelectValue>
|
||||
</CustomSelectTrigger>
|
||||
<CustomSelectContent>
|
||||
<CustomSelectItem value="image">Image</CustomSelectItem>
|
||||
<CustomSelectItem value="video">Video</CustomSelectItem>
|
||||
<CustomSelectItem value="both">Both</CustomSelectItem>
|
||||
</CustomSelectContent>
|
||||
</CustomSelect>
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue