11'use client' ;
22
3- import { useState , useEffect } from 'react' ;
3+ import { useState , useEffect , useCallback } from 'react' ;
44import { TemplateService } from '@/lib/db/services/templateService' ;
55import { VariableService } from '@/lib/db/services/variableService' ;
66import { Template , Variable } from '@/types' ;
77import { TemplateEditor } from '@/components/template-editor' ;
88import { VariableForm } from '@/components/variable-form' ;
99import { Tabs , TabsContent , TabsList , TabsTrigger } from '@/components/ui/tabs' ;
10+ import { Input } from '@/components/ui/input' ;
11+ import { MultiSelect } from '@/components/ui/multi-select' ;
1012
1113export default function TemplateManagerPage ( ) {
1214 const [ variables , setVariables ] = useState < Variable [ ] > ( [ ] ) ;
1315 const [ templates , setTemplates ] = useState < Template [ ] > ( [ ] ) ;
1416 const [ selectedTemplate , setSelectedTemplate ] = useState < Template | null > ( null ) ;
1517 const [ loading , setLoading ] = useState ( true ) ;
18+ const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
19+ const [ selectedCategories , setSelectedCategories ] = useState < string [ ] > ( [ ] ) ;
20+ const [ tags , setTags ] = useState ( '' ) ;
21+ const [ error , setError ] = useState < string | null > ( null ) ;
1622
1723 useEffect ( ( ) => {
18- loadData ( ) ;
24+ const init = async ( ) => {
25+ await TemplateService . initializeDefaultTemplates ( ) ;
26+ await VariableService . initializeDefaultVariables ( ) ;
27+ } ;
28+ init ( ) ;
1929 } , [ ] ) ;
2030
21- const loadData = async ( ) => {
31+ const loadData = useCallback ( async ( ) => {
2232 try {
2333 setLoading ( true ) ;
34+
35+ const templatesData = await TemplateService . getFilteredTemplates ( {
36+ searchQuery,
37+ categories : selectedCategories ,
38+ tags : tags . split ( ',' ) . map ( t => t . trim ( ) ) . filter ( t => t ) ,
39+ } ) ;
2440
25- // Initialize default data if needed
26- await TemplateService . initializeDefaultTemplates ( ) ;
27- await VariableService . initializeDefaultVariables ( ) ;
28-
29- // Load data
30- const [ templatesData , variablesData ] = await Promise . all ( [
31- TemplateService . getAllTemplates ( ) ,
32- VariableService . getAllVariables ( )
33- ] ) ;
41+ const variablesData = await VariableService . getAllVariables ( ) ;
3442
3543 setTemplates ( templatesData ) ;
3644 setVariables ( variablesData ) ;
3745
3846 if ( templatesData . length > 0 ) {
3947 setSelectedTemplate ( templatesData [ 0 ] ) ;
48+ } else {
49+ setSelectedTemplate ( null ) ;
4050 }
4151 } catch ( error ) {
4252 console . error ( 'Error loading data:' , error ) ;
4353 } finally {
4454 setLoading ( false ) ;
4555 }
46- } ;
56+ } , [ searchQuery , selectedCategories , tags ] ) ;
57+
58+ useEffect ( ( ) => {
59+ loadData ( ) ;
60+ } , [ loadData ] ) ;
4761 const handleCreateTemplate = async ( ) => {
48- const newTemplate = await TemplateService . createTemplate ( {
49- name : 'Untitled' ,
50- category : 'blog' ,
51- content : 'New content...' ,
52- } ) ;
53- setTemplates ( [ newTemplate , ...templates ] ) ;
54- setSelectedTemplate ( newTemplate ) ;
62+ try {
63+ setError ( null ) ;
64+ const newTemplate = await TemplateService . createTemplate ( {
65+ name : 'Untitled' ,
66+ category : 'blog' ,
67+ content : 'New content...' ,
68+ } ) ;
69+ setTemplates ( [ newTemplate , ...templates ] ) ;
70+ setSelectedTemplate ( newTemplate ) ;
71+ } catch ( err ) {
72+ setError ( 'Failed to create template.' ) ;
73+ }
5574 } ;
5675
5776 const handleVariableChange = async ( key : string , value : string ) => {
@@ -71,6 +90,23 @@ export default function TemplateManagerPage() {
7190 }
7291 } ;
7392
93+ const getHighlightedText = ( text : string , highlight : string ) => {
94+ if ( ! highlight ) return < span > { text } </ span > ;
95+ const escaped = highlight . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
96+ const parts = text . split ( new RegExp ( `(${ escaped } )` , 'gi' ) ) ;
97+ return (
98+ < span >
99+ { parts . map ( ( part , i ) =>
100+ part . toLowerCase ( ) === highlight . toLowerCase ( ) ? (
101+ < strong key = { i } > { part } </ strong >
102+ ) : (
103+ part
104+ )
105+ ) }
106+ </ span >
107+ ) ;
108+ } ;
109+
74110 if ( loading ) {
75111 return (
76112 < div className = "min-h-screen bg-background flex items-center justify-center" >
@@ -91,9 +127,36 @@ export default function TemplateManagerPage() {
91127 Create and manage your professional templates with ease
92128 </ p >
93129 </ div >
94- < button onClick = { handleCreateTemplate } className = "btn btn-primary" >
95- + New Template
96- </ button >
130+ < div className = "flex justify-between items-center" >
131+ < div className = "flex gap-4" >
132+ < Input
133+ placeholder = "Search templates..."
134+ value = { searchQuery }
135+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
136+ className = "max-w-xs"
137+ />
138+ < MultiSelect
139+ options = { [
140+ { label : 'Email' , value : 'email' } ,
141+ { label : 'Blog' , value : 'blog' } ,
142+ { label : 'Social' , value : 'social' } ,
143+ ] }
144+ onValueChange = { setSelectedCategories }
145+ defaultValue = { selectedCategories }
146+ placeholder = "Filter by category"
147+ />
148+ < Input
149+ placeholder = "Filter by tags (comma-separated)"
150+ value = { tags }
151+ onChange = { ( e ) => setTags ( e . target . value ) }
152+ className = "max-w-xs"
153+ />
154+ </ div >
155+ < button onClick = { handleCreateTemplate } className = "btn btn-primary" >
156+ + New Template
157+ </ button >
158+ </ div >
159+ { error && < p className = "text-red-500" > { error } </ p > }
97160
98161 < div className = "grid md:grid-cols-2 gap-8" >
99162 < VariableForm
@@ -111,7 +174,7 @@ export default function TemplateManagerPage() {
111174 value = { template . id }
112175 onClick = { ( ) => setSelectedTemplate ( template ) }
113176 >
114- { template . name }
177+ { getHighlightedText ( template . name , searchQuery ) }
115178 </ TabsTrigger >
116179 ) ) }
117180 </ TabsList >
0 commit comments