diff --git a/src/components/GenerateCourse/AICourseActions.tsx b/src/components/GenerateCourse/AICourseActions.tsx new file mode 100644 index 000000000..3ac19ff90 --- /dev/null +++ b/src/components/GenerateCourse/AICourseActions.tsx @@ -0,0 +1,109 @@ +import { MoreVertical, X } from 'lucide-react'; +import { useRef, useState } from 'react'; +import { useOutsideClick } from '../../hooks/use-outside-click'; +import { useKeydown } from '../../hooks/use-keydown'; +import { useToast } from '../../hooks/use-toast'; +import { useMutation } from '@tanstack/react-query'; +import { queryClient } from '../../stores/query-client'; +import { httpDelete } from '../../lib/query-http'; + +type AICourseActionsType = { + courseSlug: string; + onDeleted?: () => void; +}; + +export function AICourseActions(props: AICourseActionsType) { + const { courseSlug, onDeleted } = props; + + const toast = useToast(); + const dropdownRef = useRef(null); + + const [isOpen, setIsOpen] = useState(false); + const [isConfirming, setIsConfirming] = useState(false); + + const { mutate: deleteCourse, isPending: isDeleting } = useMutation( + { + mutationFn: async () => { + return httpDelete(`/v1-delete-ai-course/${courseSlug}`); + }, + onSuccess: () => { + toast.success('Course deleted'); + queryClient.invalidateQueries({ + predicate: (query) => query.queryKey?.[0] === 'user-ai-courses', + }); + onDeleted?.(); + }, + onError: (error) => { + toast.error(error?.message || 'Failed to delete course'); + }, + }, + queryClient, + ); + + useOutsideClick(dropdownRef, () => { + setIsOpen(false); + }); + + useKeydown('Escape', () => { + setIsOpen(false); + }); + + return ( +
+ + + {isOpen && ( +
+ {!isConfirming && ( + + )} + + {isConfirming && ( + + Are you sure? +
+ + +
+
+ )} +
+ )} +
+ ); +} diff --git a/src/components/GenerateCourse/AICourseCard.tsx b/src/components/GenerateCourse/AICourseCard.tsx index 329969ade..5528232c9 100644 --- a/src/components/GenerateCourse/AICourseCard.tsx +++ b/src/components/GenerateCourse/AICourseCard.tsx @@ -1,6 +1,7 @@ import type { AICourseWithLessonCount } from '../../queries/ai-course'; import type { DifficultyLevel } from './AICourse'; import { BookOpen } from 'lucide-react'; +import { AICourseActions } from './AICourseActions'; type AICourseCardProps = { course: AICourseWithLessonCount; @@ -32,42 +33,50 @@ export function AICourseCard(props: AICourseCardProps) { totalTopics > 0 ? Math.round((completedTopics / totalTopics) * 100) : 0; return ( - -
- - {course.difficulty} - -
+
+ +
+ + {course.difficulty} + +
-

- {course.title} -

+

+ {course.title} +

-
-
- - {totalTopics} lessons -
+
+
+ + {totalTopics} lessons +
- {totalTopics > 0 && ( -
- + + + {course.slug && ( +
+ +
+ )} +
); }