11"use client" ;
22
3- import { useState , useCallback , useMemo , useRef , type ReactNode } from "react" ;
3+ import { useState , useCallback , useEffect , useMemo , type ReactNode } from "react" ;
44import { useAgent } from "@copilotkit/react-core/v2" ;
55import { SEED_TEMPLATES } from "@/components/template-library/seed-templates" ;
66
@@ -35,25 +35,29 @@ export function SaveTemplateOverlay({
3535 const [ saveState , setSaveState ] = useState < SaveState > ( "idle" ) ;
3636 const [ templateName , setTemplateName ] = useState ( "" ) ;
3737
38- // Capture pending_template at mount time — it may be cleared by the agent later
38+ // Capture pending_template once — it may be cleared by the agent later.
39+ // Syncs external agent state into local state (legitimate effect-based setState).
3940 const pending = agent . state ?. pending_template as { id : string ; name : string } | null | undefined ;
40- const sourceRef = useRef < { id : string ; name : string } | null > ( null ) ;
41- if ( pending ?. id && ! sourceRef . current ) {
42- sourceRef . current = pending ;
43- }
41+ const [ capturedSource , setCapturedSource ] = useState < { id : string ; name : string } | null > ( null ) ;
42+ useEffect ( ( ) => {
43+ if ( pending ?. id ) {
44+ // eslint-disable-next-line react-hooks/set-state-in-effect -- one-time capture of external agent state
45+ setCapturedSource ( ( prev ) => prev ?? pending ) ;
46+ }
47+ } , [ pending ] ) ;
4448
4549 // Check if this content matches an existing template:
4650 // 1. Exact HTML match (seed templates rendered as-is)
4751 // 2. Source template captured from pending_template (applied templates with modified data)
4852 const matchedTemplate = useMemo ( ( ) => {
4953 // First check source template from apply flow
50- if ( sourceRef . current ) {
54+ if ( capturedSource ) {
5155 const allTemplates = [
5256 ...SEED_TEMPLATES ,
5357 ...( ( agent . state ?. templates as { id : string ; name : string } [ ] ) || [ ] ) ,
5458 ] ;
55- const source = allTemplates . find ( ( t ) => t . id === sourceRef . current ! . id ) ;
56- if ( source ) return source ;
59+ const found = allTemplates . find ( ( t ) => t . id === capturedSource . id ) ;
60+ if ( found ) return found ;
5761 }
5862 // Then check exact HTML match
5963 if ( ! html ) return null ;
@@ -64,7 +68,7 @@ export function SaveTemplateOverlay({
6468 ...( ( agent . state ?. templates as { id : string ; name : string ; html : string } [ ] ) || [ ] ) ,
6569 ] ;
6670 return allTemplates . find ( ( t ) => t . html && normalise ( t . html ) === norm ) ?? null ;
67- } , [ html , agent . state ?. templates ] ) ;
71+ } , [ html , agent . state ?. templates , capturedSource ] ) ;
6872
6973 const handleSave = useCallback ( ( ) => {
7074 const name = templateName . trim ( ) || title || "Untitled Template" ;
0 commit comments