@@ -103,114 +103,115 @@ export default function AdminTicketsPage() {
103103 </ div >
104104 </ div >
105105
106- < div className = "grid gap-6 " >
106+ < div className = "grid gap-3 " >
107107 { tickets . length === 0 ? (
108- < div className = "text-center py-20 bg-gray-50 rounded-xl border-2 border-dashed border-gray-200" >
109- < MessageCircle className = "w-12 h-12 text-gray-300 mx-auto mb-4" />
110- < h3 className = "text-xl font-medium text-gray-900" > No tickets yet</ h3 >
111- < p className = "text-gray-500" > User inquiries will appear here.</ p >
108+ < div className = "text-center py-20 bg-white rounded-3xl border border-dashed border-gray-200 shadow-sm " >
109+ < MessageCircle className = "w-12 h-12 text-gray-200 mx-auto mb-4" />
110+ < h3 className = "text-xl font-black text-gray-900 tracking-tight " > No inquiries yet</ h3 >
111+ < p className = "text-sm text- gray-400 font-medium" > Seeker inquiries will appear here.</ p >
112112 </ div >
113113 ) : (
114114 tickets . map ( ( ticket ) => (
115- < div key = { ticket . id } className = { `bg-white rounded-xl shadow-sm border transition-all ${ expandedTicketId === ticket . id ? 'ring-2 ring-ochre border-transparent' : 'border-gray-200' } ` } >
116- { /* Ticket Summary Header */ }
117- < div
118- onClick = { ( ) => setExpandedTicketId ( expandedTicketId === ticket . id ? null : ticket . id ) }
119- className = "p-4 md:p-6 cursor-pointer hover:bg-gray-50 flex items-center justify-between"
120- >
121- < div className = "flex items-start space-x-3 md:space-x-4 min-w-0 flex-1" >
122- < div className = "w-10 h-10 md:w-12 md:h-12 bg-gray-100 rounded-xl overflow-hidden flex-none border border-gray-100 shadow-sm" >
123- { ticket . user . image ? (
124- < img src = { ticket . user . image } alt = { ticket . user . name || '' } className = "w-full h-full object-cover" />
125- ) : (
126- < div className = "w-full h-full flex items-center justify-center" >
127- < User className = "w-5 h-5 text-gray-400" />
128- </ div >
129- ) }
130- </ div >
131- < div className = "min-w-0 flex-1" >
132- < div className = "flex flex-wrap items-center gap-2" >
133- < h3 className = "font-bold text-sm md:text-lg text-gray-900 truncate max-w-[150px] md:max-w-none" > { ticket . subject } </ h3 >
134- < span className = { `px-2 py-0.5 rounded-md text-[8px] md:text-[10px] font-black uppercase tracking-widest ${ ticket . status === 'OPEN' ? 'bg-orange-100 text-ochre' :
135- ticket . status === 'ANSWERED' ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-600'
136- } `} >
137- { ticket . status }
138- </ span >
139- </ div >
140- < div className = "flex flex-wrap items-center text-[10px] md:text-sm text-gray-500 mt-1 gap-x-2 gap-y-1" >
141- < span className = "font-bold text-gray-700 truncate max-w-[100px] md:max-w-none" > { ticket . user . name || ticket . user . email } </ span >
142- < span className = "hidden xs:inline text-gray-300" > •</ span >
143- < span className = "flex items-center" > < Clock className = "w-3 h-3 mr-1 opacity-60" /> { new Date ( ticket . createdAt ) . toLocaleDateString ( ) } </ span >
144- < span className = "hidden xs:inline text-gray-300" > •</ span >
145- < span className = "bg-gray-100 px-1.5 py-0.5 rounded font-medium" > { ticket . messages . length } msg</ span >
115+ < div
116+ key = { ticket . id }
117+ onClick = { ( ) => setExpandedTicketId ( ticket . id ) }
118+ className = "bg-white p-4 rounded-2xl shadow-sm border border-gray-100 flex items-center justify-between gap-3 cursor-pointer hover:border-ochre/30 transition-all active:scale-[0.98]"
119+ >
120+ < div className = "flex items-start gap-3 min-w-0 flex-1" >
121+ < div className = "w-10 h-10 bg-gray-50 rounded-xl overflow-hidden flex-none border border-gray-100" >
122+ { ticket . user . image ? (
123+ < img src = { ticket . user . image } alt = { ticket . user . name || '' } className = "w-full h-full object-cover" />
124+ ) : (
125+ < div className = "w-full h-full flex items-center justify-center" >
126+ < User className = "w-5 h-5 text-gray-300" />
146127 </ div >
128+ ) }
129+ </ div >
130+ < div className = "min-w-0 flex-1" >
131+ < div className = "flex items-center gap-2 mb-0.5" >
132+ < h3 className = "font-bold text-sm text-gray-900 truncate" > { ticket . subject } </ h3 >
133+ < span className = { `px-1.5 py-0.5 rounded text-[8px] font-black uppercase tracking-widest flex-none ${ ticket . status === 'OPEN' ? 'bg-orange-100 text-ochre' :
134+ ticket . status === 'ANSWERED' ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-500'
135+ } `} >
136+ { ticket . status }
137+ </ span >
138+ </ div >
139+ < div className = "flex items-center text-[10px] text-gray-400 font-bold uppercase tracking-tight gap-2" >
140+ < span className = "truncate" > { ticket . user . name || 'Anonymous' } </ span >
141+ < span className = "opacity-30" > •</ span >
142+ < span > { new Date ( ticket . createdAt ) . toLocaleDateString ( ) } </ span >
147143 </ div >
148144 </ div >
149- < div className = "ml-4 flex-none" >
150- { expandedTicketId === ticket . id ? < ChevronUp className = "w-5 h-5 text-gray-300" /> : < ChevronDown className = "w-5 h-5 text-gray-300" /> }
145+ </ div >
146+ < div className = "flex flex-col items-end gap-1 flex-none" >
147+ < div className = "bg-gray-50 px-2 py-0.5 rounded-md text-[9px] font-black text-gray-400 border border-gray-100" >
148+ { ticket . messages . length } MSG
151149 </ div >
152150 </ div >
151+ </ div >
152+ ) )
153+ ) }
154+ </ div >
153155
154- { /* Expanded Content */ }
155- { expandedTicketId === ticket . id && (
156- < div className = "border-t border-gray-100 bg-gray-50 rounded-b-xl" >
157- { /* Message Thread */ }
158- < div className = "p-4 md:p-6 space-y-4 max-h-[400px] overflow-y-auto no-scrollbar" >
159- { ticket . messages . map ( ( msg , idx ) => (
160- < div key = { idx } className = { `flex ${ msg . sender === 'USER' ? 'justify-start' : 'justify-end' } ` } >
161- < div className = { `max-w-[90%] md:max-w-[85%] rounded-2xl p-3 md:p-4 shadow-sm ${ msg . sender === 'USER'
162- ? 'bg-white border border-gray-100 text-gray-800 rounded-tl-none'
163- : 'bg-ochre text-white rounded-tr-none'
164- } `} >
165- < p className = "text-xs md:text-sm leading-relaxed font-medium" > { msg . text } </ p >
166- < div className = { `text-[9px] md:text-[10px] mt-2 font-black uppercase tracking-widest ${ msg . sender === 'USER' ? 'text-gray-400' : 'text-orange-100/70' } ` } >
167- { new Date ( msg . createdAt ) . toLocaleString ( ) }
168- </ div >
169- </ div >
170- </ div >
171- ) ) }
156+ { /* Conversation Focused Modal */ }
157+ < Modal
158+ isOpen = { ! ! expandedTicketId }
159+ onClose = { ( ) => setExpandedTicketId ( null ) }
160+ title = { tickets . find ( t => t . id === expandedTicketId ) ?. subject || 'Inquiry' }
161+ >
162+ < div className = "flex flex-col h-[60vh] -mx-6 -mt-4" >
163+ { /* Thread Content */ }
164+ < div className = "flex-1 overflow-y-auto p-4 space-y-3 no-scrollbar bg-gray-50/50" >
165+ { tickets . find ( t => t . id === expandedTicketId ) ?. messages . map ( ( msg , idx ) => (
166+ < div key = { idx } className = { `flex ${ msg . sender === 'USER' ? 'justify-start' : 'justify-end' } ` } >
167+ < div className = { `max-w-[90%] rounded-2xl px-3 py-2 shadow-sm ${ msg . sender === 'USER'
168+ ? 'bg-white border border-gray-100 text-gray-800 rounded-tl-none'
169+ : 'bg-ochre text-white rounded-tr-none shadow-ochre/20'
170+ } `} >
171+ < p className = "text-xs font-medium leading-relaxed" > { msg . text } </ p >
172+ < div className = { `text-[8px] mt-1 font-black uppercase tracking-widest ${ msg . sender === 'USER' ? 'text-gray-300' : 'text-orange-100/70'
173+ } `} >
174+ { new Date ( msg . createdAt ) . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } ) }
172175 </ div >
176+ </ div >
177+ </ div >
178+ ) ) }
179+ </ div >
173180
174- { /* Action Area */ }
175- { ticket . status !== 'CLOSED' && (
176- < div className = "p-4 md:p-6 border-t border-gray-100 bg-white rounded-b-xl space-y-4" >
177- < div className = "relative" >
178- < textarea
179- value = { replyText [ ticket . id ] || '' }
180- onChange = { ( e ) => setReplyText ( prev => ( { ...prev , [ ticket . id ] : e . target . value } ) ) }
181- placeholder = "Type your spiritual guidance here..."
182- rows = { 3 }
183- className = "w-full border border-gray-100 rounded-xl p-3 md:p-4 focus:ring-2 focus:ring-ochre/20 focus:border-ochre outline-none text-sm resize-none bg-gray-50/50"
184- />
185- </ div >
186- < div className = "flex flex-col sm:flex-row items-center justify-between gap-4" >
187- < button
188- onClick = { ( ) => setConfirmCloseId ( ticket . id ) }
189- className = "w-full sm:w-auto text-gray-400 hover:text-red-500 text-[10px] md:text-xs font-bold uppercase tracking-widest flex items-center justify-center transition-all px-3 py-2 rounded-lg hover:bg-red-50"
190- >
191- < CheckCircle2 className = "w-4 h-4 mr-2" /> Close Inquiry
192- </ button >
193- < button
194- disabled = { isSubmitting [ ticket . id ] || ! replyText [ ticket . id ] ?. trim ( ) }
195- onClick = { ( ) => handleReply ( ticket . id ) }
196- className = "w-full sm:w-auto bg-ochre text-white px-8 py-3 rounded-xl font-black text-xs uppercase tracking-widest hover:bg-orange-700 transition-all disabled:opacity-50 flex items-center justify-center shadow-lg shadow-ochre/20 active:scale-95"
197- >
198- { isSubmitting [ ticket . id ] ? (
199- < Loader2 className = "w-4 h-4 mr-2 animate-spin" />
200- ) : (
201- < Send className = "w-4 h-4 mr-2" />
202- ) }
203- Send Guidance
204- </ button >
205- </ div >
206- </ div >
181+ { /* Footer / Reply Area */ }
182+ { expandedTicketId && tickets . find ( t => t . id === expandedTicketId ) ?. status !== 'CLOSED' && (
183+ < div className = "p-4 bg-white border-t border-gray-100 space-y-3" >
184+ < textarea
185+ value = { replyText [ expandedTicketId ] || '' }
186+ onChange = { ( e ) => setReplyText ( prev => ( { ...prev , [ expandedTicketId ! ] : e . target . value } ) ) }
187+ placeholder = "Type spiritual guidance..."
188+ rows = { 2 }
189+ className = "w-full border-none bg-gray-50 rounded-xl p-3 text-xs font-medium focus:ring-2 focus:ring-ochre/20 outline-none resize-none"
190+ />
191+ < div className = "flex items-center justify-between gap-3" >
192+ < button
193+ onClick = { ( ) => setConfirmCloseId ( expandedTicketId ) }
194+ className = "text-[9px] font-black text-gray-300 uppercase tracking-widest hover:text-red-500 transition-colors py-2"
195+ >
196+ Close Inquiry
197+ </ button >
198+ < button
199+ disabled = { isSubmitting [ expandedTicketId ] || ! replyText [ expandedTicketId ] ?. trim ( ) }
200+ onClick = { ( ) => handleReply ( expandedTicketId ! ) }
201+ className = "bg-ochre text-white px-6 py-2.5 rounded-xl font-black text-[10px] uppercase tracking-widest hover:bg-orange-700 transition-all disabled:opacity-30 shadow-lg shadow-ochre/20 flex items-center"
202+ >
203+ { isSubmitting [ expandedTicketId ] ? (
204+ < Loader2 className = "w-3 h-3 mr-2 animate-spin" />
205+ ) : (
206+ < Send className = "w-3 h-3 mr-2" />
207207 ) }
208- </ div >
209- ) }
208+ Send
209+ </ button >
210+ </ div >
210211 </ div >
211- ) )
212- ) }
213- </ div >
212+ ) }
213+ </ div >
214+ </ Modal >
214215
215216 { /* Premium UI Components */ }
216217 < Modal
0 commit comments