feat: enhance ConceptExplainer to handle content extraction and display; add normalization for PocketBase records
This commit is contained in:
@@ -1,19 +1,42 @@
|
||||
import Card from '../ui/Card';
|
||||
import Button from '../ui/Button';
|
||||
|
||||
/**
|
||||
* Safely extract sections from a content object that may be:
|
||||
* - a properly parsed object: { sections: [...] }
|
||||
* - a JSON string: '{"sections":[...]}'
|
||||
* - null / undefined
|
||||
*
|
||||
* Returns an array in every case so .map() never throws.
|
||||
*/
|
||||
function getSections(content) {
|
||||
let obj = content;
|
||||
if (typeof obj === 'string') {
|
||||
try { obj = JSON.parse(obj); } catch { return []; }
|
||||
}
|
||||
const sections = obj?.sections;
|
||||
return Array.isArray(sections) ? sections : [];
|
||||
}
|
||||
|
||||
export default function ConceptExplainer({ content, onComplete }) {
|
||||
const sections = getSections(content);
|
||||
|
||||
return (
|
||||
<Card className="w-full h-[60vh] flex flex-col p-0">
|
||||
<div className="p-6 border-b border-bg-warm">
|
||||
<h2 className="text-xl font-bold">Concept Explainer</h2>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto p-6 prose dark:prose-invert">
|
||||
{content?.sections?.map((section, i) => (
|
||||
<div key={i} className="mb-6">
|
||||
<h3>{section.title}</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: section.content }} />
|
||||
</div>
|
||||
))}
|
||||
{sections.length === 0 ? (
|
||||
<p className="text-fg-muted italic">No content available for this topic yet.</p>
|
||||
) : (
|
||||
sections.map((section, i) => (
|
||||
<div key={i} className="mb-6">
|
||||
<h3>{section.title}</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: section.content }} />
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4 border-t border-bg-warm flex justify-end">
|
||||
<Button onClick={onComplete}>Finish session</Button>
|
||||
|
||||
Reference in New Issue
Block a user