feat: implement AI-driven learning content generation service and interactive student dashboard
This commit is contained in:
@@ -34,7 +34,7 @@ const ContentManager = () => {
|
||||
const handleRegenerate = async (topic) => {
|
||||
setTopicState(topic.id, { loading: 'regenerating', error: null, success: null });
|
||||
try {
|
||||
await generateLearningContent(topic, true);
|
||||
await generateLearningContent(topic, true, 'all');
|
||||
setTopicState(topic.id, { loading: null, success: 'Content regenerated.' });
|
||||
refresh();
|
||||
} catch (e) {
|
||||
|
||||
@@ -20,8 +20,17 @@ const MODES = [
|
||||
{ key: 'infographic', icon: BarChart2, label: 'Infographic' },
|
||||
];
|
||||
|
||||
const LearningContentViewer = ({ content, topic, initialMode = 'article' }) => {
|
||||
const [activeMode, setActiveMode] = useState(initialMode);
|
||||
const LearningContentViewer = ({ content, topic, initialMode = 'article', onGenerate, isLoading }) => {
|
||||
const populatedModes = MODES.filter(m => m.key === 'podcast' ? !!content?.podcastScript : !!content?.[m.key]);
|
||||
const defaultMode = populatedModes.length > 0 ? populatedModes[0].key : initialMode;
|
||||
const [activeMode, setActiveMode] = useState(defaultMode);
|
||||
|
||||
// If content populates while we are on an empty tab, keep the tab active
|
||||
useEffect(() => {
|
||||
if (content && populatedModes.length === 1 && !populatedModes.find(m => m.key === activeMode)) {
|
||||
setActiveMode(populatedModes[0].key);
|
||||
}
|
||||
}, [content]);
|
||||
|
||||
if (!content || !topic) return null;
|
||||
|
||||
@@ -54,10 +63,26 @@ const LearningContentViewer = ({ content, topic, initialMode = 'article' }) => {
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
{activeMode === 'article' && <ArticleView content={content.article} />}
|
||||
{activeMode === 'slides' && <SlidesView slides={content.slides} />}
|
||||
{activeMode === 'podcast' && <PodcastView script={content.podcastScript} topicLabel={topic.label} />}
|
||||
{activeMode === 'infographic' && <InfographicView data={content.infographic} topicLabel={topic.label} />}
|
||||
{(() => {
|
||||
const isPopulated = activeMode === 'podcast' ? !!content?.podcastScript : !!content?.[activeMode];
|
||||
if (!isPopulated) {
|
||||
return (
|
||||
<Card className="border border-bg-warm text-center py-16">
|
||||
<p className="text-fg-muted mb-6">This content has not been generated yet.</p>
|
||||
{onGenerate && (
|
||||
<Button onClick={() => onGenerate(activeMode)} disabled={isLoading}>
|
||||
Generate {MODES.find(m => m.key === activeMode)?.label}
|
||||
</Button>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
if (activeMode === 'article') return <ArticleView content={content.article} />;
|
||||
if (activeMode === 'slides') return <SlidesView slides={content.slides} />;
|
||||
if (activeMode === 'podcast') return <PodcastView script={content.podcastScript} topicLabel={topic.label} />;
|
||||
if (activeMode === 'infographic') return <InfographicView data={content.infographic} topicLabel={topic.label} />;
|
||||
return null;
|
||||
})()}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user