()
| 76 | } |
| 77 | |
| 78 | export function NotificationsPanel() { |
| 79 | const { state, dispatch } = useNotifications(); |
| 80 | const [isVisible, _setIsVisible] = useState(false); |
| 81 | const { connection } = useRobotConnection(); |
| 82 | const { t } = useLanguage(); |
| 83 | |
| 84 | // Mark all as read when panel becomes visible |
| 85 | useEffect(() => { |
| 86 | if (isVisible) { |
| 87 | state.notifications.forEach((notification) => { |
| 88 | if (!notification.read) { |
| 89 | dispatch({ type: 'MARK_AS_READ', payload: notification.id }); |
| 90 | } |
| 91 | }); |
| 92 | } |
| 93 | }, [isVisible, state.notifications, dispatch]); |
| 94 | |
| 95 | return ( |
| 96 | <AnimatePresence> |
| 97 | <motion.div |
| 98 | initial={{ opacity: 0, x: '100%' }} |
| 99 | animate={{ opacity: 1, x: 0 }} |
| 100 | exit={{ opacity: 0, x: '100%' }} |
| 101 | transition={{ type: 'spring', damping: 20, stiffness: 300 }} |
| 102 | className="fixed inset-y-0 right-0 w-80 bg-[#f0d5ff] dark:bg-botbot-darker shadow-2xl z-[100] flex flex-col" |
| 103 | > |
| 104 | {/* Header */} |
| 105 | <div className="p-4 border-b dark:border-botbot-dark bg-white dark:bg-botbot-dark"> |
| 106 | <div className="flex items-center justify-between"> |
| 107 | <div className="flex items-center gap-2"> |
| 108 | <Robot className="w-5 h-5 text-[#821db7] dark:text-white" /> |
| 109 | <h3 className="text-lg font-semibold">{t('notifications', 'title')}</h3> |
| 110 | </div> |
| 111 | <button |
| 112 | onClick={() => dispatch({ type: 'CLEAR_ALL' })} |
| 113 | className="text-xs text-gray-500 hover:text-gray-700 dark:text-white dark:hover:text-gray-300" |
| 114 | > |
| 115 | {t('notifications', 'markAllAsRead')} |
| 116 | </button> |
| 117 | </div> |
| 118 | </div> |
| 119 | |
| 120 | {/* Notifications list */} |
| 121 | <div className="flex-1 overflow-y-auto p-4 space-y-3"> |
| 122 | <AnimatePresence mode="popLayout"> |
| 123 | {state.notifications.length === 0 ? ( |
| 124 | <motion.div |
| 125 | initial={{ opacity: 0 }} |
| 126 | animate={{ opacity: 1 }} |
| 127 | className="flex flex-col items-center justify-center h-full text-gray-500 dark:text-white" |
| 128 | > |
| 129 | <Robot className="w-12 h-12 mb-4 opacity-50" /> |
| 130 | <p className="text-sm">{t('notifications', 'noNotifications')}</p> |
| 131 | <p className="text-xs mt-2 text-center max-w-[200px]"> |
| 132 | Robot events and system notifications will appear here |
| 133 | </p> |
| 134 | </motion.div> |
| 135 | ) : ( |
nothing calls this directly
no test coverage detected