11import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query"
22import { createFileRoute } from "@tanstack/react-router"
3+ import { Check , Copy } from "lucide-react"
34import { useEffect , useMemo , useState } from "react"
4-
55import { Button } from "@/components/ui/button"
66import {
77 Card ,
@@ -11,6 +11,7 @@ import {
1111 CardTitle ,
1212} from "@/components/ui/card"
1313import { Input } from "@/components/ui/input"
14+ import { useCopyToClipboard } from "@/hooks/useCopyToClipboard"
1415import useCustomToast from "@/hooks/useCustomToast"
1516import {
1617 createGeneration ,
@@ -19,12 +20,11 @@ import {
1920 getTemplate ,
2021 listTemplates ,
2122 listTemplateVersions ,
22- renderTemplate ,
2323 type Template ,
2424 type TemplateVariableConfig ,
2525 type TemplateVersion ,
2626} from "@/lib/templateMvpApi"
27- import { errorToMessage } from "@/lib/templateVariables"
27+ import { errorToMessage , renderTemplateText } from "@/lib/templateVariables"
2828
2929function listToInput ( value : unknown ) : string {
3030 if ( ! Array . isArray ( value ) ) {
@@ -103,6 +103,7 @@ export const Route = createFileRoute("/_layout/generate")({
103103function GeneratePage ( ) {
104104 const queryClient = useQueryClient ( )
105105 const { showErrorToast, showSuccessToast } = useCustomToast ( )
106+ const [ copiedText , copy ] = useCopyToClipboard ( )
106107
107108 const [ selectedTemplateId , setSelectedTemplateId ] = useState < string > ( "" )
108109 const [ selectedVersionId , setSelectedVersionId ] = useState < string > ( "" )
@@ -168,10 +169,6 @@ function GeneratePage() {
168169 mutationFn : extractVariables ,
169170 } )
170171
171- const renderMutation = useMutation ( {
172- mutationFn : renderTemplate ,
173- } )
174-
175172 const saveGenerationMutation = useMutation ( {
176173 mutationFn : createGeneration ,
177174 } )
@@ -192,6 +189,7 @@ function GeneratePage() {
192189 if ( ! currentVersion ) {
193190 setValues ( { } )
194191 setMissingRequired ( [ ] )
192+ setOutputText ( "" )
195193 return
196194 }
197195
@@ -208,8 +206,14 @@ function GeneratePage() {
208206 }
209207 setValues ( initialValues )
210208 setMissingRequired ( [ ] )
211- setOutputText ( "" )
212- } , [ currentVersion ?. id , currentVersion ] )
209+ } , [ currentVersion ] )
210+
211+ useEffect ( ( ) => {
212+ if ( ! currentVersion ) {
213+ return
214+ }
215+ setOutputText ( renderTemplateText ( currentVersion . content , values ) )
216+ } , [ currentVersion , values ] )
213217
214218 const handleExtract = async ( ) => {
215219 if ( ! selectedVersionId ) {
@@ -235,28 +239,6 @@ function GeneratePage() {
235239 }
236240 }
237241
238- const handleRender = async ( ) => {
239- if ( ! selectedVersionId ) {
240- showErrorToast ( "Select a template version first" )
241- return
242- }
243-
244- try {
245- const result = await renderMutation . mutateAsync ( {
246- template_version_id : selectedVersionId ,
247- values,
248- style : {
249- tone : "professional" ,
250- length : "medium" ,
251- } ,
252- } )
253- setOutputText ( result . output_text )
254- showSuccessToast ( "Draft generated" )
255- } catch ( error ) {
256- showErrorToast ( errorToMessage ( error ) )
257- }
258- }
259-
260242 const handleSaveGeneration = async ( ) => {
261243 if ( ! selectedTemplateId || ! selectedVersionId || ! outputText . trim ( ) ) {
262244 showErrorToast ( "Generate content before saving" )
@@ -319,6 +301,19 @@ function GeneratePage() {
319301 setMissingRequired ( ( current ) => current . filter ( ( item ) => item !== variable ) )
320302 }
321303
304+ const handleCopyOutput = async ( ) => {
305+ const text = outputText . trim ( )
306+ if ( ! text ) {
307+ showErrorToast ( "Nothing to copy" )
308+ return
309+ }
310+
311+ const ok = await copy ( outputText )
312+ if ( ! ok ) {
313+ showErrorToast ( "Copy failed" )
314+ }
315+ }
316+
322317 return (
323318 < div className = "space-y-6" >
324319 < div >
@@ -392,7 +387,7 @@ function GeneratePage() {
392387 < CardHeader >
393388 < CardTitle > Step C: Confirm Variables</ CardTitle >
394389 < CardDescription >
395- Fill missing required fields before generating .
390+ Fill missing required fields. Output updates in real time .
396391 </ CardDescription >
397392 </ CardHeader >
398393 < CardContent className = "space-y-4" >
@@ -440,19 +435,26 @@ function GeneratePage() {
440435 Select a template version to load variables.
441436 </ p >
442437 ) }
443-
444- < Button
445- onClick = { handleRender }
446- disabled = { renderMutation . isPending || ! currentVersion }
447- >
448- Generate Draft
449- </ Button >
450438 </ CardContent >
451439 </ Card >
452440
453441 < Card >
454- < CardHeader >
442+ < CardHeader className = "flex flex-row items-center justify-between" >
455443 < CardTitle > Step D: Output</ CardTitle >
444+ < Button
445+ variant = "outline"
446+ size = "sm"
447+ className = "gap-2"
448+ onClick = { handleCopyOutput }
449+ disabled = { ! outputText . trim ( ) }
450+ >
451+ { copiedText === outputText ? (
452+ < Check className = "size-4 text-green-500" />
453+ ) : (
454+ < Copy className = "size-4" />
455+ ) }
456+ { copiedText === outputText ? "Copied" : "test" }
457+ </ Button >
456458 </ CardHeader >
457459 < CardContent className = "space-y-3" >
458460 < textarea
0 commit comments