@@ -34,9 +34,9 @@ import { createLogger } from '@/lib/logs/console/logger'
3434import { getBaseUrl } from '@/lib/urls/utils'
3535import { cn } from '@/lib/utils'
3636import type { CredentialRequirement } from '@/lib/workflows/credential-extractor'
37- import type { Template } from '@/app/templates/templates'
3837import { WorkflowPreview } from '@/app/workspace/[workspaceId]/w/components/workflow-preview/workflow-preview'
3938import { getBlock } from '@/blocks/registry'
39+ import { useStarTemplate , useTemplate } from '@/hooks/queries/templates'
4040
4141const logger = createLogger ( 'TemplateDetails' )
4242
@@ -52,16 +52,14 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
5252 const workspaceId = isWorkspaceContext ? ( params ?. workspaceId as string ) : null
5353 const { data : session } = useSession ( )
5454
55- const [ template , setTemplate ] = useState < Template | null > ( null )
55+ const { data : template , isLoading : loading } = useTemplate ( templateId )
56+ const starTemplate = useStarTemplate ( )
57+
5658 const [ currentUserOrgs , setCurrentUserOrgs ] = useState < string [ ] > ( [ ] )
5759 const [ currentUserOrgRoles , setCurrentUserOrgRoles ] = useState <
5860 Array < { organizationId : string ; role : string } >
5961 > ( [ ] )
6062 const [ isSuperUser , setIsSuperUser ] = useState ( false )
61- const [ loading , setLoading ] = useState ( true )
62- const [ isStarred , setIsStarred ] = useState ( false )
63- const [ starCount , setStarCount ] = useState ( 0 )
64- const [ isStarring , setIsStarring ] = useState ( false )
6563 const [ isUsing , setIsUsing ] = useState ( false )
6664 const [ isEditing , setIsEditing ] = useState ( false )
6765 const [ isApproving , setIsApproving ] = useState ( false )
@@ -76,29 +74,7 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
7674
7775 const currentUserId = session ?. user ?. id || null
7876
79- // Fetch template data on client side
8077 useEffect ( ( ) => {
81- if ( ! templateId ) {
82- setLoading ( false )
83- return
84- }
85-
86- const fetchTemplate = async ( ) => {
87- try {
88- const response = await fetch ( `/api/templates/${ templateId } ` )
89- if ( response . ok ) {
90- const data = await response . json ( )
91- setTemplate ( data . data )
92- setIsStarred ( data . data . isStarred || false )
93- setStarCount ( data . data . stars || 0 )
94- }
95- } catch ( error ) {
96- logger . error ( 'Error fetching template:' , error )
97- } finally {
98- setLoading ( false )
99- }
100- }
101-
10278 const fetchUserOrganizations = async ( ) => {
10379 if ( ! currentUserId ) return
10480
@@ -134,12 +110,10 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
134110 }
135111 }
136112
137- fetchTemplate ( )
138113 fetchSuperUserStatus ( )
139114 fetchUserOrganizations ( )
140- } , [ templateId , currentUserId ] )
115+ } , [ currentUserId ] )
141116
142- // Fetch workspaces when user is logged in
143117 useEffect ( ( ) => {
144118 if ( ! currentUserId ) return
145119
@@ -149,7 +123,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
149123 const response = await fetch ( '/api/workspaces' )
150124 if ( response . ok ) {
151125 const data = await response . json ( )
152- // Filter workspaces where user has write/admin permissions
153126 const availableWorkspaces = data . workspaces
154127 . filter ( ( ws : any ) => ws . permissions === 'write' || ws . permissions === 'admin' )
155128 . map ( ( ws : any ) => ( {
@@ -169,7 +142,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
169142 fetchWorkspaces ( )
170143 } , [ currentUserId ] )
171144
172- // Clean up URL when returning from login
173145 useEffect ( ( ) => {
174146 if ( template && searchParams ?. get ( 'use' ) === 'true' && currentUserId ) {
175147 if ( isWorkspaceContext && workspaceId ) {
@@ -181,26 +153,20 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
181153 }
182154 } , [ searchParams , currentUserId , template , isWorkspaceContext , workspaceId , router ] )
183155
184- // Check if user can edit template
185156 const canEditTemplate = ( ( ) => {
186157 if ( ! currentUserId || ! template ?. creator ) return false
187158
188- // For user creator profiles: must be the user themselves
189159 if ( template . creator . referenceType === 'user' ) {
190160 return template . creator . referenceId === currentUserId
191161 }
192162
193- // For organization creator profiles:
194163 if ( template . creator . referenceType === 'organization' && template . creator . referenceId ) {
195164 const isOrgMember = currentUserOrgs . includes ( template . creator . referenceId )
196165
197- // If template has a connected workflow, any org member with workspace access can edit
198166 if ( template . workflowId ) {
199167 return isOrgMember
200168 }
201169
202- // If template is orphaned, only admin/owner can edit
203- // We need to check the user's role in the organization
204170 const orgMembership = currentUserOrgRoles . find (
205171 ( org ) => org . organizationId === template . creator ?. referenceId
206172 )
@@ -212,7 +178,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
212178 return false
213179 } ) ( )
214180
215- // Check workspace access for connected workflow
216181 useEffect ( ( ) => {
217182 const checkWorkspaceAccess = async ( ) => {
218183 if ( ! template ?. workflowId || ! currentUserId || ! canEditTemplate ) {
@@ -227,7 +192,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
227192 } else if ( checkResponse . ok ) {
228193 setHasWorkspaceAccess ( true )
229194 } else {
230- // Workflow doesn't exist
231195 setHasWorkspaceAccess ( null )
232196 }
233197 } catch ( error ) {
@@ -319,32 +283,20 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
319283 * @param event - The wheel event fired when the user scrolls over the preview area.
320284 */
321285 const handleCanvasWheelCapture = ( event : React . WheelEvent < HTMLDivElement > ) => {
322- // Allow pinch/zoom gestures (e.g., ctrl/cmd + wheel) to continue to the canvas.
323286 if ( event . ctrlKey || event . metaKey ) {
324287 return
325288 }
326289
327- // Prevent React Flow from handling the wheel; let the page scroll naturally.
328290 event . stopPropagation ( )
329291 }
330292
331293 const handleStarToggle = async ( ) => {
332- if ( isStarring || ! currentUserId ) return
333-
334- setIsStarring ( true )
335- try {
336- const method = isStarred ? 'DELETE' : 'POST'
337- const response = await fetch ( `/api/templates/${ template . id } /star` , { method } )
294+ if ( ! currentUserId || ! template ) return
338295
339- if ( response . ok ) {
340- setIsStarred ( ! isStarred )
341- setStarCount ( ( prev ) => ( isStarred ? prev - 1 : prev + 1 ) )
342- }
343- } catch ( error ) {
344- logger . error ( 'Error toggling star:' , error )
345- } finally {
346- setIsStarring ( false )
347- }
296+ starTemplate . mutate ( {
297+ templateId : template . id ,
298+ action : template . isStarred ? 'remove' : 'add' ,
299+ } )
348300 }
349301
350302 const handleUseTemplate = ( ) => {
@@ -357,7 +309,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
357309 return
358310 }
359311
360- // In workspace context, use current workspace directly
361312 if ( isWorkspaceContext && workspaceId ) {
362313 handleWorkspaceSelectForUse ( workspaceId )
363314 }
@@ -366,7 +317,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
366317 const handleEditTemplate = async ( ) => {
367318 if ( ! currentUserId || ! template ) return
368319
369- // In workspace context with existing workflow, navigate directly
370320 if ( isWorkspaceContext && workspaceId && template . workflowId ) {
371321 setIsEditing ( true )
372322 try {
@@ -381,10 +331,8 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
381331 } finally {
382332 setIsEditing ( false )
383333 }
384- // If workflow doesn't exist, fall through to workspace selector
385334 }
386335
387- // Check if workflow exists and user has access (global context)
388336 if ( template . workflowId && ! isWorkspaceContext ) {
389337 setIsEditing ( true )
390338 try {
@@ -410,7 +358,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
410358 }
411359 }
412360
413- // Workflow doesn't exist - show workspace selector or use current workspace
414361 if ( isWorkspaceContext && workspaceId ) {
415362 handleWorkspaceSelectForEdit ( workspaceId )
416363 } else {
@@ -435,7 +382,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
435382
436383 const { workflowId } = await response . json ( )
437384
438- // Navigate to the new workflow with full page load
439385 window . location . href = `/workspace/${ workspaceId } /w/${ workflowId } `
440386 } catch ( error ) {
441387 logger . error ( 'Error using template:' , error )
@@ -450,7 +396,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
450396 setIsUsing ( true )
451397 setShowWorkspaceSelectorForEdit ( false )
452398 try {
453- // Import template as a new workflow and connect it to the template
454399 const response = await fetch ( `/api/templates/${ template . id } /use` , {
455400 method : 'POST' ,
456401 headers : { 'Content-Type' : 'application/json' } ,
@@ -463,7 +408,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
463408
464409 const { workflowId } = await response . json ( )
465410
466- // Navigate to the new workflow with full page load
467411 window . location . href = `/workspace/${ workspaceId } /w/${ workflowId } `
468412 } catch ( error ) {
469413 logger . error ( 'Error importing template for editing:' , error )
@@ -482,9 +426,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
482426 } )
483427
484428 if ( response . ok ) {
485- // Update template status optimistically
486- setTemplate ( { ...template , status : 'approved' } )
487- // Redirect back to templates page after approval
488429 if ( isWorkspaceContext && workspaceId ) {
489430 router . push ( `/workspace/${ workspaceId } /templates` )
490431 } else {
@@ -508,9 +449,6 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
508449 } )
509450
510451 if ( response . ok ) {
511- // Update template status optimistically
512- setTemplate ( { ...template , status : 'rejected' } )
513- // Redirect back to templates page after rejection
514452 if ( isWorkspaceContext && workspaceId ) {
515453 router . push ( `/workspace/${ workspaceId } /templates` )
516454 } else {
@@ -752,11 +690,11 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
752690 onClick = { handleStarToggle }
753691 className = { cn (
754692 'h-[14px] w-[14px] cursor-pointer transition-colors' ,
755- isStarred ? 'fill-yellow-500 text-yellow-500' : 'text-[#888888]' ,
756- isStarring && 'opacity-50'
693+ template . isStarred ? 'fill-yellow-500 text-yellow-500' : 'text-[#888888]' ,
694+ starTemplate . isPending && 'opacity-50'
757695 ) }
758696 />
759- < span className = 'font-medium text-[#888888] text-[14px]' > { starCount } </ span >
697+ < span className = 'font-medium text-[#888888] text-[14px]' > { template . stars || 0 } </ span >
760698
761699 { /* Users icon and count */ }
762700 < ChartNoAxesColumn className = 'h-[16px] w-[16px] text-[#888888]' />
0 commit comments