import { useEffect, useState, useMemo } from 'react' import { InboxItem, Page } from '../types' import { getInboxItems, respondToDelegation } from '../api' import { colors } from '../constants' import Pagination, { PAGE_SIZE } from '../components/Pagination' interface InboxPageProps { onNavigate: (page: Page, name?: string) => void onRefresh?: () => void } const typeToPage: Record = { process: 'processes-form', order: 'orders-form', incident: 'incidents-form', idea: 'ideas-form', } const typeColor: Record = { process: '#3b82f6', order: '#8b5cf6', incident: '#ef4444', idea: '#10b981', delegation: '#f59e0b', } const typeGradient: Record = { process: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)', order: 'linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%)', incident: 'linear-gradient(135deg, #ef4444 0%, #b91c1c 100%)', idea: 'linear-gradient(135deg, #10b981 0%, #047857 100%)', delegation: 'linear-gradient(135deg, #f59e0b 0%, #b45309 100%)', } const typeIcon: Record = { process: '⚙️', order: '📦', incident: '🚨', idea: '💡', delegation: '🤝', } export default function InboxPage({ onNavigate, onRefresh }: InboxPageProps) { const [items, setItems] = useState([]) const [loading, setLoading] = useState(true) const [busyName, setBusyName] = useState('') const [errorName, setErrorName] = useState('') const [search, setSearch] = useState('') const [filterType, setFilterType] = useState('all') const [page, setPage] = useState(1) const load = () => { setLoading(true) getInboxItems().then(data => { setItems(data || []) setLoading(false) }).catch(() => setLoading(false)) } useEffect(() => { load() }, []) const counts = useMemo(() => { const res: Record = { all: items.length, action: 0, info: 0 } for (const item of items) { if (item.requires_action) res.action = (res.action || 0) + 1 else res.info = (res.info || 0) + 1 res[item.type] = (res[item.type] || 0) + 1 } return res }, [items]) const filteredItems = useMemo(() => { return items.filter(item => { if (filterType === 'action' && !item.requires_action) return false if (filterType === 'info' && item.requires_action) return false if (filterType !== 'all' && filterType !== 'action' && filterType !== 'info' && item.type !== filterType) return false if (search.trim()) { const q = search.toLowerCase() const match = [item.number, item.title, item.action, item.organization, item.type].filter(Boolean).join(' ').toLowerCase() if (!match.includes(q)) return false } return true }) }, [items, filterType, search]) useEffect(() => { setPage(1) }, [filterType, search]) const pageItems = filteredItems.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE) const respond = async (name: string, response: 'Accepted' | 'Rejected') => { setBusyName(name) setErrorName('') try { await respondToDelegation(name, response) await load() onRefresh?.() } catch { setErrorName(name) } finally { setBusyName('') } } return (
{/* Top Banner & Stats */}
{/* Glow decoration */}
📬

Unified Activity Inbox

Real-time tasks, approvals, delegations, and workflow actions requiring your attention.

{/* Quick stat counters */}
Total Items {counts.all || 0}
Action Required {counts.action || 0}
Informational {counts.info || 0}
{/* Filter Tabs and Search Bar */}
{/* Pills */}
{[ { id: 'all', label: 'All', icon: '📋', count: counts.all }, { id: 'action', label: 'Needs Action', icon: '🚨', count: counts.action, badgeColor: '#ef4444' }, { id: 'info', label: 'Info', icon: 'ℹ️', count: counts.info }, { id: 'incident', label: 'Incidents', icon: '⚠️', count: counts.incident }, { id: 'idea', label: 'Ideas', icon: '💡', count: counts.idea }, { id: 'order', label: 'Orders', icon: '📦', count: counts.order }, { id: 'process', label: 'Processes', icon: '⚙️', count: counts.process }, { id: 'delegation', label: 'Delegations', icon: '🤝', count: counts.delegation }, ].map(tab => { const active = filterType === tab.id if (tab.id !== 'all' && tab.id !== 'action' && tab.id !== 'info' && (!tab.count || tab.count === 0)) return null return ( ) })}
{/* Search */}
setSearch(e.target.value)} style={{ width: '100%', padding: '7px 12px', borderRadius: 8, border: '1px solid #cbd5e1', fontSize: 12, boxSizing: 'border-box', background: '#f8fafc', color: '#334155' }} />
{/* Cards List */} {loading ? (
⏳
Loading inbox updates…
) : filteredItems.length === 0 ? (
✨

{search || filterType !== 'all' ? 'No matching inbox items' : 'You are all caught up!'}

{search || filterType !== 'all' ? 'Try changing your filter pills or searching for a different keyword.' : 'There are no active pending approvals or tasks requiring your action right now.'}

{(search || filterType !== 'all') && ( )}
) : (
{pageItems.map((item, idx) => { const tint = typeColor[item.type] || colors.gray const gradient = typeGradient[item.type] || 'linear-gradient(135deg, #64748b 0%, #475569 100%)' const clickable = item.type !== 'delegation' return (
onNavigate(typeToPage[item.type] as Page, item.name) : undefined} style={{ background: 'white', borderRadius: 14, padding: '16px 18px', border: '1px solid #e2e8f0', boxShadow: '0 1px 3px rgba(0,0,0,0.04)', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', gap: 14, cursor: clickable ? 'pointer' : 'default', position: 'relative', overflow: 'hidden', transition: 'transform 0.15s ease, box-shadow 0.15s ease' }} onMouseEnter={e => { if (clickable) { (e.currentTarget as HTMLElement).style.transform = 'translateY(-2px)' ;(e.currentTarget as HTMLElement).style.boxShadow = '0 10px 20px -5px rgba(0,0,0,0.08)' } }} onMouseLeave={e => { if (clickable) { (e.currentTarget as HTMLElement).style.transform = 'none' ;(e.currentTarget as HTMLElement).style.boxShadow = '0 1px 3px rgba(0,0,0,0.04)' } }} > {/* Accent line */}
{/* Card Header row */}
{typeIcon[item.type] || '📌'}
{item.number || item.name}
{item.requires_action ? ( Action ) : ( {item.type} )}
{/* Card Title */}
{item.title || item.action || 'Untitled Item'}
{/* Action description / remarks */}
{item.action}
{/* Meta tag chips */}
{item.organization && ( 🏢 {item.organization} )} {item.date && ( 📅 {item.date} )}
{errorName === item.name && (
⚠️ Failed to process response. Please try again.
)}
{/* Footer Action */}
{item.type === 'delegation' ? (
) : ( )}
) })}
)}
) }