11import { useState , useEffect , useCallback } from 'react' ;
22import { motion , AnimatePresence } from 'framer-motion' ;
33import { AlertTriangle , Check , X , Clock , DollarSign , Building2 , Shield , ChevronDown , CheckCircle } from 'lucide-react' ;
4+ import { useSearchParams } from 'react-router-dom' ;
45import { apiFetch } from '../lib/api' ;
6+ import { useClients } from '../hooks/useClients' ;
57
68const stagger = {
79 hidden : { } ,
@@ -27,6 +29,7 @@ interface Escalation {
2729 approved_by : string | null ;
2830 denial_reason : string | null ;
2931 approval_token : string | null ;
32+ client_id : string | null ;
3033 created_at : string ;
3134 expires_at : string ;
3235 resolved_at : string | null ;
@@ -81,20 +84,28 @@ function timeUntilExpiry(expiresAt: string): string {
8184}
8285
8386export const EscalationsPage : React . FC = ( ) => {
87+ const [ searchParams ] = useSearchParams ( ) ;
88+ const { clients } = useClients ( ) ;
89+ const clientMap = new Map ( clients . map ( c => [ c . id , c . name ] ) ) ;
90+
8491 const [ escalations , setEscalations ] = useState < Escalation [ ] > ( [ ] ) ;
8592 const [ loading , setLoading ] = useState ( true ) ;
8693 const [ filter , setFilter ] = useState < string > ( 'all' ) ;
94+ const [ clientFilter , setClientFilter ] = useState < string > ( searchParams . get ( 'client_id' ) || 'all' ) ;
8795 const [ expandedId , setExpandedId ] = useState < string | null > ( null ) ;
8896 const [ acting , setActing ] = useState < string | null > ( null ) ;
8997
9098 const fetchEscalations = useCallback ( async ( ) => {
9199 try {
92- const params = filter !== 'all' ? `?status=${ filter } ` : '' ;
93- const resp = await apiFetch ( `/v1/escalations${ params } ` ) ;
100+ const qp = new URLSearchParams ( ) ;
101+ if ( filter !== 'all' ) qp . set ( 'status' , filter ) ;
102+ if ( clientFilter !== 'all' ) qp . set ( 'client_id' , clientFilter ) ;
103+ const qs = qp . toString ( ) ;
104+ const resp = await apiFetch ( `/v1/escalations${ qs ? `?${ qs } ` : '' } ` ) ;
94105 if ( resp . ok ) setEscalations ( await resp . json ( ) ) ;
95106 } catch { /* degrade silently */ }
96107 setLoading ( false ) ;
97- } , [ filter ] ) ;
108+ } , [ filter , clientFilter ] ) ;
98109
99110 useEffect ( ( ) => {
100111 fetchEscalations ( ) ;
@@ -139,20 +150,37 @@ export const EscalationsPage: React.FC = () => {
139150 </ p >
140151 </ div >
141152
142- < div className = "flex gap-1.5" >
143- { [ 'all' , 'pending' , 'approved' , 'denied' , 'expired' ] . map ( f => (
144- < button
145- key = { f }
146- onClick = { ( ) => setFilter ( f ) }
147- className = { `px-3 py-1.5 rounded-lg text-xs transition-colors ${
148- filter === f
149- ? 'bg-[#FAF6ED] text-[#B08D3E] border border-[#E8DCC4]'
150- : 'bg-white border border-[#E8E5DE] text-[#6B6760] hover:bg-[#F7F6F3]'
151- } `}
153+ < div className = "flex items-center gap-3" >
154+ { /* Client filter */ }
155+ { clients . length > 0 && (
156+ < select
157+ value = { clientFilter }
158+ onChange = { e => setClientFilter ( e . target . value ) }
159+ className = "bg-white border border-[#E8E5DE] text-[#6B6760] text-xs rounded-lg px-3 py-1.5 focus:outline-none focus:border-[#B08D3E] transition-colors"
152160 >
153- { f . charAt ( 0 ) . toUpperCase ( ) + f . slice ( 1 ) }
154- </ button >
155- ) ) }
161+ < option value = "all" > All Clients</ option >
162+ { clients . map ( c => (
163+ < option key = { c . id } value = { c . id } > { c . name } </ option >
164+ ) ) }
165+ </ select >
166+ ) }
167+
168+ { /* Status filters */ }
169+ < div className = "flex gap-1.5" >
170+ { [ 'all' , 'pending' , 'approved' , 'denied' , 'expired' ] . map ( f => (
171+ < button
172+ key = { f }
173+ onClick = { ( ) => setFilter ( f ) }
174+ className = { `px-3 py-1.5 rounded-lg text-xs transition-colors ${
175+ filter === f
176+ ? 'bg-[#FAF6ED] text-[#B08D3E] border border-[#E8DCC4]'
177+ : 'bg-white border border-[#E8E5DE] text-[#6B6760] hover:bg-[#F7F6F3]'
178+ } `}
179+ >
180+ { f . charAt ( 0 ) . toUpperCase ( ) + f . slice ( 1 ) }
181+ </ button >
182+ ) ) }
183+ </ div >
156184 </ div >
157185 </ motion . div >
158186
@@ -199,7 +227,15 @@ export const EscalationsPage: React.FC = () => {
199227 ) }
200228 { confidenceBadge ( esc . vendor_confidence ) }
201229 </ div >
202- < p className = "text-xs text-[#6B6760] mt-0.5 truncate" > { esc . agent_name } - { esc . reason } </ p >
230+ < p className = "text-xs text-[#6B6760] mt-0.5 truncate" >
231+ { esc . agent_name }
232+ { esc . client_id && clientMap . get ( esc . client_id ) && (
233+ < span className = "ml-1.5 text-[10px] px-1.5 py-0.5 rounded bg-[#F7F6F3] text-[#9C978E] border border-[#F0EDE6]" >
234+ { clientMap . get ( esc . client_id ) }
235+ </ span >
236+ ) }
237+ < span className = "mx-1 text-[#E8E5DE]" > -</ span > { esc . reason }
238+ </ p >
203239 </ div >
204240 </ div >
205241
0 commit comments