107 lines
4.1 KiB
TypeScript
107 lines
4.1 KiB
TypeScript
import React from 'react';
|
||
import { useDemoStore } from '../../mock/store';
|
||
import { Drawer } from '../../shared/components/Drawer';
|
||
import { Button } from '../../shared/components/Button';
|
||
import { Bell, AlertTriangle, AlertCircle, CheckCircle2, Info, Check, Trash2 } from 'lucide-react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
|
||
export const NotificationsDrawer: React.FC = () => {
|
||
const {
|
||
isNotificationsOpen,
|
||
setIsNotificationsOpen,
|
||
notifications,
|
||
dismissNotification,
|
||
markAllNotificationsRead,
|
||
} = useDemoStore();
|
||
|
||
const navigate = useNavigate();
|
||
|
||
const getIcon = (type: string) => {
|
||
switch (type) {
|
||
case 'danger':
|
||
return <AlertCircle className="w-4 h-4 text-krona-danger" />;
|
||
case 'warning':
|
||
return <AlertTriangle className="w-4 h-4 text-krona-warning" />;
|
||
case 'success':
|
||
return <CheckCircle2 className="w-4 h-4 text-krona-green" />;
|
||
default:
|
||
return <Info className="w-4 h-4 text-krona-info" />;
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Drawer
|
||
isOpen={isNotificationsOpen}
|
||
onClose={() => setIsNotificationsOpen(false)}
|
||
title="Центр внимания и уведомлений"
|
||
subtitle="Срочные алерты, статус кассы, стоп-листы и опоздания"
|
||
width="md"
|
||
footer={
|
||
<div className="w-full flex items-center justify-between">
|
||
<Button variant="ghost" size="sm" onClick={markAllNotificationsRead}>
|
||
<Check className="w-3.5 h-3.5 mr-1.5" />
|
||
Прочитать все
|
||
</Button>
|
||
<Button variant="secondary" size="sm" onClick={() => setIsNotificationsOpen(false)}>
|
||
Закрыть
|
||
</Button>
|
||
</div>
|
||
}
|
||
>
|
||
<div className="space-y-3">
|
||
{notifications.length === 0 ? (
|
||
<div className="py-12 text-center text-krona-secondary text-xs">
|
||
<Bell className="w-8 h-8 mx-auto mb-2 opacity-30" />
|
||
Нет активных уведомлений. Все системы в норме!
|
||
</div>
|
||
) : (
|
||
notifications.map((n) => (
|
||
<div
|
||
key={n.id}
|
||
className={`p-3.5 rounded-lg border transition-all ${
|
||
n.read
|
||
? 'bg-krona-surface/40 border-krona-border/60 opacity-80'
|
||
: 'bg-krona-surface border-krona-border shadow-krona-soft'
|
||
}`}
|
||
>
|
||
<div className="flex items-start gap-2.5">
|
||
<div className="mt-0.5 shrink-0">{getIcon(n.type)}</div>
|
||
<div className="flex-1 min-w-0">
|
||
<div className="flex items-center justify-between gap-2 mb-1">
|
||
<h5 className="text-xs font-semibold text-krona-primary truncate">{n.title}</h5>
|
||
<span className="text-[10px] text-krona-secondary whitespace-nowrap">{n.timestamp}</span>
|
||
</div>
|
||
<p className="text-xs text-krona-secondary leading-relaxed">{n.message}</p>
|
||
|
||
<div className="mt-2.5 flex items-center justify-between pt-1 border-t border-krona-border/40">
|
||
{n.actionUrl ? (
|
||
<button
|
||
onClick={() => {
|
||
setIsNotificationsOpen(false);
|
||
navigate(n.actionUrl!);
|
||
}}
|
||
className="text-xs text-krona-green font-medium hover:underline"
|
||
>
|
||
Перейти к решению →
|
||
</button>
|
||
) : (
|
||
<span />
|
||
)}
|
||
|
||
<button
|
||
onClick={() => dismissNotification(n.id)}
|
||
className="text-krona-secondary hover:text-krona-danger p-1 rounded"
|
||
title="Удалить"
|
||
>
|
||
<Trash2 className="w-3.5 h-3.5" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
</Drawer>
|
||
);
|
||
};
|