"use client"; import { useState, useEffect, useCallback } from "react"; export function GenerateTab({ importType }: { importType: "flashcards" | "quizzes" | "connections" | "crossword" }) { const [instructions, setInstructions] = useState(""); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [saveResult, setSaveResult] = useState<"success" | "error" | null>(null); const [copied, setCopied] = useState(false); const [packCount, setPackCount] = useState(1); const [loadError, setLoadError] = useState(null); const batchOverride = importType === "connections" && packCount > 1 ? `TEMPORARY BATCH OVERRIDE:\nGenerate exactly ${packCount} distinct Connections packs. Return one raw JSON array containing exactly ${packCount} objects that each follow the schema below. Make the packs meaningfully different from one another. This override takes precedence over any later instruction to return one object.\n\n` : ""; const displayedInstructions = `${batchOverride}${instructions}`; const loadInstructions = useCallback(async (signal?: AbortSignal) => { setLoading(true); setLoadError(null); try { const response = await fetch(`/api/settings/llm-instructions?type=${importType}`, { signal }); if (!response.ok) throw new Error("Instructions could not be loaded."); const data = await response.json() as { value?: unknown }; if (typeof data.value !== "string") throw new Error("The server returned invalid instructions."); setInstructions(data.value); } catch (error) { if (signal?.aborted) return; setLoadError(error instanceof Error ? error.message : "Instructions could not be loaded."); } finally { if (!signal?.aborted) setLoading(false); } }, [importType]); useEffect(() => { const controller = new AbortController(); const timer = window.setTimeout(() => void loadInstructions(controller.signal), 0); return () => { window.clearTimeout(timer); controller.abort(); }; }, [loadInstructions]); async function handleSave() { setSaving(true); setSaveResult(null); try { const res = await fetch(`/api/settings/llm-instructions?type=${importType}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: instructions }), }); if (!res.ok) throw new Error("Failed to save"); setSaveResult("success"); } catch { setSaveResult("error"); } finally { setSaving(false); setTimeout(() => setSaveResult(null), 2500); } } async function handleReset() { if (!confirm("Reset to default instructions?")) return; setSaving(true); try { const res = await fetch(`/api/settings/llm-instructions?type=${importType}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: "__RESET__" }), }); if (!res.ok) throw new Error("Failed to reset instructions"); const data = await res.json(); if (typeof data.value !== "string") throw new Error("Invalid reset response"); setInstructions(data.value); setSaveResult("success"); } catch { setSaveResult("error"); } finally { setSaving(false); } } async function handleCopy() { try { await navigator.clipboard.writeText(displayedInstructions); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { setLoadError("Clipboard access failed. Select and copy the instructions manually."); } } if (loading) { return
Loading instructions...
; } if (loadError && !instructions) { return (

{loadError}

); } return (
{loadError &&

{loadError}

}

Copy these instructions and paste them into an LLM chat along with your study material. The LLM will generate JSON you can paste into the Import tab.

{importType === "connections" && (

This temporarily updates the copied prompt. Your saved instructions stay unchanged.

{packCount}
setPackCount(Number(event.target.value))} className="mt-4 w-full accent-primary" />
1510
)}