← back to Dw Boardroom Governance

frontend/src/components/EscalationQueue.tsx

58 lines

import { api } from '../api';
import { useApi } from '../hooks/useApi';

export default function EscalationQueue() {
  const { data: escalations, refresh } = useApi(() => api.getActiveEscalations(), []);

  async function triggerCheck() {
    try {
      await api.triggerEscalationCheck();
      refresh();
    } catch (err: any) {
      console.error('[EscalationQueue] triggerCheck failed:', err.message);
    }
  }

  return (
    <div style={styles.card}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
        <h3 style={styles.cardTitle}>Escalation Queue</h3>
        <button style={styles.checkBtn} onClick={triggerCheck}>Run Check</button>
      </div>

      <div style={styles.list}>
        {(!escalations || escalations.length === 0) && (
          <div style={styles.empty}>No active escalations. Decisions past the threshold will appear here.</div>
        )}
        {escalations?.map((e: any) => (
          <div key={e.id} style={styles.item}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <span style={{ fontWeight: 600, fontSize: 13 }}>{e.topic || 'Unknown topic'}</span>
              <span style={styles.timeBadge}>{e.hours_elapsed}h elapsed</span>
            </div>
            <div style={{ fontSize: 11, color: '#7a7f96', marginTop: 4 }}>
              Owner: {e.owner} | Type: {e.escalation_type} | Action: {e.action_taken}
            </div>
            {e.decision_status && (
              <span style={{ ...styles.statusBadge, marginTop: 6, display: 'inline-block' }}>
                Decision: {e.decision_status}
              </span>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

const styles: Record<string, React.CSSProperties> = {
  card: { background: '#1a1a2e', borderRadius: 12, padding: 20, border: '1px solid #252540' },
  cardTitle: { margin: 0, fontSize: 15, fontWeight: 700 },
  checkBtn: { padding: '6px 14px', borderRadius: 6, border: 'none', background: '#ef444433', color: '#ef4444', fontWeight: 600, fontSize: 11, cursor: 'pointer', fontFamily: 'inherit' },
  list: { display: 'flex', flexDirection: 'column', gap: 8 },
  empty: { color: '#7a7f96', fontSize: 13, textAlign: 'center' as const, padding: 30 },
  item: { background: '#12121f', borderRadius: 8, padding: 12, border: '1px solid #ef444433' },
  timeBadge: { padding: '2px 10px', borderRadius: 4, fontSize: 11, fontWeight: 700, background: '#ef444422', color: '#ef4444' },
  statusBadge: { padding: '2px 8px', borderRadius: 4, fontSize: 10, fontWeight: 600, background: '#f59e0b22', color: '#f59e0b' },
};