feat: create new course

feat/create-new-course^2
Arik Chakma 3 days ago
parent 4401a4c9aa
commit df4230c62d
  1. 54
      src/components/TopicDetail/CreateCourseModal.tsx
  2. 24
      src/components/TopicDetail/TopicDetail.tsx
  3. 13
      src/components/TopicDetail/TopicDetailAI.tsx

@ -0,0 +1,54 @@
import { ChevronRightIcon, SearchIcon } from 'lucide-react';
import { Modal } from '../Modal';
type CreateCourseModalProps = {
onClose: () => void;
};
export function CreateCourseModal(props: CreateCourseModalProps) {
const { onClose } = props;
return (
<Modal
onClose={onClose}
wrapperClassName="h-auto mt-20"
overlayClassName="items-start"
bodyClassName="p-1.5"
>
<form
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const subject = formData.get('subject');
window.location.href = `/ai/search?term=${subject}&difficulty=beginner&src=topic`;
onClose();
}}
>
<label
className="mb-2.5 ml-1 inline-block text-sm leading-none"
htmlFor="subject"
>
Subject
</label>
<div className="relative overflow-hidden rounded-lg border">
<input
id="subject"
type="text"
className="w-full bg-white p-2.5 px-8 text-sm focus:bg-gray-50 focus:outline-hidden"
placeholder="Enter a Subject for the Course"
name="subject"
autoFocus={true}
/>
<div className="absolute top-0 left-0 flex h-full items-center justify-center px-2 text-gray-500">
<SearchIcon className="size-4" />
</div>
<button className="absolute top-0 right-0 flex h-full items-center justify-center px-2 hover:bg-gray-200">
<ChevronRightIcon className="size-4" />
</button>
</div>
</form>
</Modal>
);
}

@ -42,6 +42,7 @@ import { cn } from '../../lib/classname.ts';
import type { AIChatHistoryType } from '../GenerateCourse/AICourseLessonChat.tsx'; import type { AIChatHistoryType } from '../GenerateCourse/AICourseLessonChat.tsx';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal.tsx'; import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal.tsx';
import { TopicProgressButton } from './TopicProgressButton.tsx'; import { TopicProgressButton } from './TopicProgressButton.tsx';
import { CreateCourseModal } from './CreateCourseModal.tsx';
type TopicDetailProps = { type TopicDetailProps = {
resourceId?: string; resourceId?: string;
@ -119,6 +120,8 @@ export function TopicDetail(props: TopicDetailProps) {
const [showUpgradeModal, setShowUpgradeModal] = useState(false); const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [isCustomResource, setIsCustomResource] = useState(false); const [isCustomResource, setIsCustomResource] = useState(false);
const [showSubjectSearchModal, setShowSubjectSearchModal] = useState(false);
const toast = useToast(); const toast = useToast();
const [showPaidResourceDisclaimer, setShowPaidResourceDisclaimer] = const [showPaidResourceDisclaimer, setShowPaidResourceDisclaimer] =
@ -139,6 +142,7 @@ export function TopicDetail(props: TopicDetailProps) {
setShowUpgradeModal(false); setShowUpgradeModal(false);
setAiChatHistory(defaultChatHistory); setAiChatHistory(defaultChatHistory);
setActiveTab('content'); setActiveTab('content');
setShowSubjectSearchModal(false);
}; };
// Close the topic detail when user clicks outside the topic detail // Close the topic detail when user clicks outside the topic detail
@ -349,10 +353,6 @@ export function TopicDetail(props: TopicDetailProps) {
return null; return null;
} }
const resourceTitleForSearch = resourceTitle
?.toLowerCase()
?.replace(/\s+?roadmap/gi, '');
const tnsLink = const tnsLink =
'https://thenewstack.io/devops/?utm_source=roadmap.sh&utm_medium=Referral&utm_campaign=Topic'; 'https://thenewstack.io/devops/?utm_source=roadmap.sh&utm_medium=Referral&utm_campaign=Topic';
@ -362,10 +362,6 @@ export function TopicDetail(props: TopicDetailProps) {
return resource.topicIds.includes(normalizedTopicId); return resource.topicIds.includes(normalizedTopicId);
}); });
const hasPaidScrimbaLinks = paidResourcesForTopic.some(
(resource) => resource?.url?.toLowerCase().indexOf('scrimba') !== -1,
);
const shouldShowAiTab = !isCustomResource && resourceType === 'roadmap'; const shouldShowAiTab = !isCustomResource && resourceType === 'roadmap';
return ( return (
@ -379,6 +375,10 @@ export function TopicDetail(props: TopicDetailProps) {
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} /> <UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
)} )}
{showSubjectSearchModal && (
<CreateCourseModal onClose={() => setShowSubjectSearchModal(false)} />
)}
{isLoading && ( {isLoading && (
<div className="flex h-full w-full justify-center"> <div className="flex h-full w-full justify-center">
<Spinner <Spinner
@ -448,6 +448,14 @@ export function TopicDetail(props: TopicDetailProps) {
handleClose(); handleClose();
showLoginPopup(); showLoginPopup();
}} }}
onShowSubjectSearchModal={() => {
if (!isLoggedIn()) {
showLoginPopup();
return;
}
setShowSubjectSearchModal(true);
}}
/> />
)} )}

@ -11,6 +11,8 @@ import {
Gift, Gift,
Loader2Icon, Loader2Icon,
LockIcon, LockIcon,
PlusIcon,
SearchIcon,
SendIcon, SendIcon,
Trash2, Trash2,
} from 'lucide-react'; } from 'lucide-react';
@ -42,6 +44,8 @@ type TopicDetailAIProps = {
onUpgrade: () => void; onUpgrade: () => void;
onLogin: () => void; onLogin: () => void;
onShowSubjectSearchModal: () => void;
}; };
export function TopicDetailAI(props: TopicDetailAIProps) { export function TopicDetailAI(props: TopicDetailAIProps) {
@ -53,6 +57,7 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
topicId, topicId,
onUpgrade, onUpgrade,
onLogin, onLogin,
onShowSubjectSearchModal,
} = props; } = props;
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
@ -285,6 +290,14 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
))} ))}
</a> </a>
)} )}
<button
onClick={onShowSubjectSearchModal}
className="flex items-center gap-1.5 rounded-md border border-gray-300 bg-transparent px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<PlusIcon className="h-3 w-3" />
Create a Course
</button>
</div> </div>
</div> </div>
)} )}

Loading…
Cancel
Save