import { useState } from 'react'; import { Copy, Check } from 'lucide-react'; import type { Campaign, Character, Note, Quest } from '@/lib/schemas'; import { complete } from '@/lib/llm/client'; import { getLlmConfig, useAssistantStore } from '@/stores/assistantStore'; import { buildCampaignContext } from '@/lib/assistant/context'; import { buildSessionHookPrompt, sessionHookSchema, fallbackSessionHooks, type SessionHook } from '@/lib/assistant/session'; import { Button } from '@/components/ui/Button'; interface Props { campaign: Campaign; characters: Character[]; notes: Note[]; quests: Quest[]; } export function SessionPrepCard({ campaign, characters, notes, quests }: Props) { const llmEnabled = useAssistantStore((s) => s.enabled); const hasKey = useAssistantStore((s) => !!s.apiKey); const canUseLlm = llmEnabled && hasKey; const [state, setState] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle'); const [hooks, setHooks] = useState([]); const [message, setMessage] = useState(null); const generate = async () => { setState('loading'); setMessage(null); const ctx = buildCampaignContext({ campaign, characters, encounters: [], quests, notes }); if (canUseLlm) { const { system, user } = buildSessionHookPrompt(ctx); const result = await complete<{ hooks: SessionHook[] }>(getLlmConfig(), { system, user, schema: sessionHookSchema }); if (result.ok && 'data' in result) { setHooks(result.data.hooks); setState('ready'); return; } setMessage(`AI unavailable${!result.ok ? ` (${result.error})` : ''}. Showing template hooks instead.`); } setHooks(fallbackSessionHooks(ctx)); setState('ready'); }; return (

Generate three distinct session opening hooks grounded in your campaign's current threads.

{message &&

{message}

} {state === 'ready' && hooks.length > 0 && (
{hooks.map((h, i) => ( ))}
)}
); } function HookCard({ hook }: { hook: SessionHook }) { const [copied, setCopied] = useState(false); const copy = () => { void navigator.clipboard?.writeText(`${hook.title}\n\n${hook.opening}\n\n${hook.tension}`).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1500); }); }; return (
{hook.title}

{hook.opening}

{hook.tension}

); }