1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-03 06:12:53 +02:00
This commit is contained in:
Arik Chakma
2025-06-13 13:17:54 +06:00
parent 4871bb9ffd
commit 7e63cc2031
8 changed files with 153 additions and 9 deletions

View File

@@ -5,10 +5,19 @@ import {
SparklesIcon,
type LucideIcon,
} from 'lucide-react';
import { useId, useState } from 'react';
import { useEffect, useId, useState, type FormEvent } from 'react';
import { FormatItem } from './FormatItem';
import { GuideOptions } from './GuideOptions';
import { FineTuneCourse } from '../GenerateCourse/FineTuneCourse';
import { CourseOptions } from './CourseOptions';
import {
clearFineTuneData,
getCourseFineTuneData,
getLastSessionId,
storeFineTuneData,
} from '../../lib/ai';
import { isLoggedIn } from '../../lib/jwt';
import { showLoginPopup } from '../../lib/popup';
const allowedFormats = ['course', 'guide', 'roadmap'] as const;
type AllowedFormat = (typeof allowedFormats)[number];
@@ -19,6 +28,8 @@ export function ContentGenerator() {
// guide options
const [depth, setDepth] = useState('essentials');
// course options
const [difficulty, setDifficulty] = useState('beginner');
// fine-tune options
const [showFineTuneOptions, setShowFineTuneOptions] = useState(false);
@@ -51,8 +62,59 @@ export function ContentGenerator() {
},
];
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!isLoggedIn()) {
showLoginPopup();
return;
}
let sessionId = '';
if (showFineTuneOptions) {
clearFineTuneData();
sessionId = storeFineTuneData({
about,
goal,
customInstructions,
});
}
if (selectedFormat === 'course') {
window.location.href = `/ai/course?term=${encodeURIComponent(title)}&difficulty=${difficulty}&id=${sessionId}&format=${selectedFormat}`;
} else if (selectedFormat === 'guide') {
window.location.href = `/ai/guide?term=${encodeURIComponent(title)}&depth=${depth}&id=${sessionId}&format=${selectedFormat}`;
}
};
useEffect(() => {
window?.fireEvent({
action: 'tutor_user',
category: 'ai_tutor',
label: 'Visited AI Course Page',
});
}, []);
useEffect(() => {
const lastSessionId = getLastSessionId();
if (!lastSessionId) {
return;
}
const fineTuneData = getCourseFineTuneData(lastSessionId);
if (!fineTuneData) {
return;
}
setAbout(fineTuneData.about);
setGoal(fineTuneData.goal);
setCustomInstructions(fineTuneData.customInstructions);
}, []);
return (
<form className="mx-auto mt-20 w-full max-w-md space-y-4 rounded-xl bg-white p-4">
<form
className="mx-auto mt-20 w-full max-w-md space-y-4 rounded-xl bg-white p-4"
onSubmit={handleSubmit}
>
<div className="flex flex-col gap-2">
<label
htmlFor={titleFieldId}
@@ -67,6 +129,8 @@ export function ContentGenerator() {
value={title}
onChange={(e) => setTitle(e.target.value)}
className="block h-9 w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm outline-none placeholder:text-gray-500 focus:border-gray-500"
required
minLength={3}
/>
</div>
<div className="flex flex-col gap-2">
@@ -94,6 +158,10 @@ export function ContentGenerator() {
<GuideOptions depth={depth} setDepth={setDepth} />
)}
{selectedFormat === 'course' && (
<CourseOptions difficulty={difficulty} setDifficulty={setDifficulty} />
)}
{selectedFormat !== 'roadmap' && (
<>
<div className="flex h-9 items-center gap-2 rounded-lg border border-gray-200 px-3 text-sm">

View File

@@ -0,0 +1,76 @@
import { useId, useState } from 'react';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '../Select';
type CourseOptionsProps = {
difficulty: string;
setDifficulty: (difficulty: string) => void;
};
export function CourseOptions(props: CourseOptionsProps) {
const { difficulty, setDifficulty } = props;
const difficultySelectId = useId();
const difficultyOptions = [
{
label: 'Beginner',
value: 'beginner',
description: 'Covers fundamental concepts',
},
{
label: 'Intermediate',
value: 'intermediate',
description: 'Explore advanced topics',
},
{
label: 'Advanced',
value: 'advanced',
description: 'Deep dives into complex concepts',
},
];
const selectedDifficulty = difficultyOptions.find(
(option) => option.value === difficulty,
);
return (
<div className="flex flex-col gap-2">
<label
htmlFor={difficultySelectId}
className="inline-block text-sm text-gray-500"
>
Choose difficulty level
</label>
<Select value={difficulty} onValueChange={setDifficulty}>
<SelectTrigger id={difficultySelectId}>
{selectedDifficulty && (
<div className="flex flex-col gap-1">
<span>{selectedDifficulty.label}</span>
</div>
)}
{!selectedDifficulty && (
<SelectValue placeholder="Select a difficulty" />
)}
</SelectTrigger>
<SelectContent>
{difficultyOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className="flex flex-col gap-1">
<span>{option.label}</span>
<span className="text-xs text-gray-500">
{option.description}
</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
);
}

View File

@@ -6,7 +6,7 @@ import { getUrlParams } from '../../lib/browser';
import { isLoggedIn } from '../../lib/jwt';
import { getAiCourseOptions } from '../../queries/ai-course';
import { queryClient } from '../../stores/query-client';
import { AIDocumentContent } from './AIDocumentContent';
import { AIDocumentContent } from './AIGuideContent';
type GenerateAIDocumentProps = {};

View File

@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
import { generateDocument } from '../../helper/generate-ai-document';
import { queryClient } from '../../stores/query-client';
import { getAiDocumentOptions } from '../../queries/ai-document';
import { AIDocumentContent } from './AIDocumentContent';
import { AIDocumentContent } from './AIGuideContent';
type GetAIDocumentProps = {
slug: string;

View File

@@ -1,6 +1,6 @@
---
import { AITutorLayout } from '../../../components/AITutor/AITutorLayout';
import { GetAIDocument } from '../../../components/GenerateDocument/GetAIDocument';
import { GetAIDocument } from '../../../components/GenerateGuide/GetAIGuide';
import SkeletonLayout from '../../../layouts/SkeletonLayout.astro';
export const prerender = false;

View File

@@ -1,8 +1,8 @@
---
import { AITutorLayout } from '../../components/AITutor/AITutorLayout';
import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification';
import { GenerateAIDocument } from '../../components/GenerateDocument/GenerateAIDocument';
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
import { AITutorLayout } from '../../../components/AITutor/AITutorLayout';
import { CheckSubscriptionVerification } from '../../../components/Billing/CheckSubscriptionVerification';
import { GenerateAIDocument } from '../../../components/GenerateGuide/GenerateAIGuide';
import SkeletonLayout from '../../../layouts/SkeletonLayout.astro';
---
<SkeletonLayout