computer-scienceangular-roadmapbackend-roadmapblockchain-roadmapdba-roadmapdeveloper-roadmapdevops-roadmapfrontend-roadmapgo-roadmaphactoberfestjava-roadmapjavascript-roadmapnodejs-roadmappython-roadmapqa-roadmapreact-roadmaproadmapstudy-planvue-roadmapweb3-roadmap
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.5 KiB
170 lines
5.5 KiB
import { WandIcon } from 'lucide-react'; |
|
import { useEffect, useState } from 'react'; |
|
import { isLoggedIn } from '../../lib/jwt'; |
|
import { showLoginPopup } from '../../lib/popup'; |
|
import { FineTuneCourse } from './FineTuneCourse'; |
|
import { DifficultyDropdown } from '../AITutor/DifficultyDropdown'; |
|
import { |
|
clearFineTuneData, |
|
getCourseFineTuneData, |
|
getLastSessionId, |
|
storeFineTuneData, |
|
} from '../../lib/ai'; |
|
import { cn } from '../../lib/classname'; |
|
|
|
export const difficultyLevels = [ |
|
'beginner', |
|
'intermediate', |
|
'advanced', |
|
] as const; |
|
export type DifficultyLevel = (typeof difficultyLevels)[number]; |
|
|
|
type AICourseProps = {}; |
|
|
|
export function AICourse(props: AICourseProps) { |
|
const [keyword, setKeyword] = useState(''); |
|
const [difficulty, setDifficulty] = useState<DifficultyLevel>('beginner'); |
|
|
|
const [hasFineTuneData, setHasFineTuneData] = useState(false); |
|
const [about, setAbout] = useState(''); |
|
const [goal, setGoal] = useState(''); |
|
const [customInstructions, setCustomInstructions] = useState(''); |
|
|
|
useEffect(() => { |
|
const lastSessionId = getLastSessionId(); |
|
if (!lastSessionId) { |
|
return; |
|
} |
|
|
|
const fineTuneData = getCourseFineTuneData(lastSessionId); |
|
if (!fineTuneData) { |
|
return; |
|
} |
|
|
|
setAbout(fineTuneData.about); |
|
setGoal(fineTuneData.goal); |
|
setCustomInstructions(fineTuneData.customInstructions); |
|
}, []); |
|
|
|
const handleKeyDown = (e: React.KeyboardEvent) => { |
|
if (e.key === 'Enter' && keyword.trim()) { |
|
onSubmit(); |
|
} |
|
}; |
|
|
|
function onSubmit() { |
|
if (!isLoggedIn()) { |
|
showLoginPopup(); |
|
return; |
|
} |
|
|
|
let sessionId = ''; |
|
if (hasFineTuneData) { |
|
clearFineTuneData(); |
|
sessionId = storeFineTuneData({ |
|
about, |
|
goal, |
|
customInstructions, |
|
}); |
|
} |
|
|
|
window.location.href = `/ai/search?term=${encodeURIComponent(keyword)}&difficulty=${difficulty}&id=${sessionId}`; |
|
} |
|
|
|
return ( |
|
<div className="mx-auto flex w-full max-w-3xl flex-grow flex-col pt-4 md:justify-center md:pt-10 lg:pt-0"> |
|
<h1 className="mb-0.5 text-center text-4xl font-semibold max-md:text-left max-md:text-xl lg:mb-3"> |
|
What can I help you learn? |
|
</h1> |
|
<p className="mb-3 text-balance text-center text-lg text-gray-600 max-md:text-left max-md:text-sm lg:mb-6"> |
|
Enter a topic below to generate a personalized course for it |
|
</p> |
|
|
|
<div className="rounded-lg border border-gray-300 bg-white"> |
|
<form |
|
className="flex flex-col" |
|
onSubmit={(e) => { |
|
e.preventDefault(); |
|
onSubmit(); |
|
}} |
|
> |
|
<input |
|
id="keyword" |
|
type="text" |
|
value={keyword} |
|
autoFocus={true} |
|
onChange={(e) => setKeyword(e.target.value)} |
|
onKeyDown={handleKeyDown} |
|
placeholder="e.g. JavaScript Promises, React Hooks, Go Routines etc" |
|
className="w-full rounded-md border-none bg-transparent px-4 pt-4 pb-8 text-gray-900 focus:outline-hidden max-sm:placeholder:text-base" |
|
maxLength={50} |
|
/> |
|
|
|
<div className="flex flex-col items-start justify-between gap-2 px-4 pb-4 md:flex-row md:items-center"> |
|
<div className="flex flex-row items-center gap-2"> |
|
<div className="flex flex-row gap-2"> |
|
<DifficultyDropdown |
|
value={difficulty} |
|
onChange={setDifficulty} |
|
/> |
|
</div> |
|
<label |
|
htmlFor="fine-tune-checkbox" |
|
className="flex cursor-pointer flex-row items-center gap-1 rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-700 hover:bg-gray-200 hover:text-gray-700" |
|
> |
|
<input |
|
type="checkbox" |
|
checked={hasFineTuneData} |
|
onChange={() => setHasFineTuneData(!hasFineTuneData)} |
|
className="mr-1" |
|
id="fine-tune-checkbox" |
|
/> |
|
Explain more |
|
<span className="hidden md:inline"> for a better course</span> |
|
</label> |
|
</div> |
|
|
|
<button |
|
type="submit" |
|
disabled={!keyword.trim()} |
|
className={cn( |
|
'hidden items-center justify-center rounded-full px-4 py-1 text-sm text-white transition-colors md:flex', |
|
!keyword.trim() |
|
? 'cursor-not-allowed bg-gray-400' |
|
: 'bg-black hover:bg-gray-800', |
|
)} |
|
> |
|
<WandIcon size={18} className="mr-2" /> |
|
Generate Course |
|
</button> |
|
</div> |
|
|
|
<FineTuneCourse |
|
hasFineTuneData={hasFineTuneData} |
|
setHasFineTuneData={setHasFineTuneData} |
|
about={about} |
|
goal={goal} |
|
customInstructions={customInstructions} |
|
setAbout={setAbout} |
|
setGoal={setGoal} |
|
setCustomInstructions={setCustomInstructions} |
|
/> |
|
|
|
<button |
|
type="submit" |
|
disabled={!keyword.trim()} |
|
className={cn( |
|
'mx-4 mb-3 flex items-center justify-center rounded-full px-4 py-1 text-sm text-white transition-colors md:hidden', |
|
!keyword.trim() |
|
? 'cursor-not-allowed bg-gray-400' |
|
: 'bg-black hover:bg-gray-800', |
|
)} |
|
> |
|
<WandIcon size={18} className="mr-2" /> |
|
Generate Course |
|
</button> |
|
</form> |
|
</div> |
|
</div> |
|
); |
|
}
|
|
|