File size: 7,523 Bytes
149698e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import { useTranslation } from 'react-i18next';
import { CheckCircle, AlertTriangle, Store, Monitor, X } from 'lucide-react';
import { cn } from '@/lib/utils';

interface Notification {
  id: string;
  type: 'success' | 'warning' | 'info' | 'system';
  titleKey: string;
  descriptionKey: string;
  timeKey: string;
  isRead: boolean;
  actions?: { labelKey: string; variant: 'primary' | 'secondary' | 'warning' }[];
}

const todayNotifications: Notification[] = [
  {
    id: '1',
    type: 'success',
    titleKey: 'notifications.scanComplete',
    descriptionKey: 'notifications.scanCompleteDesc',
    timeKey: 'notifications.time.2mAgo',
    isRead: false,
    actions: [{ labelKey: 'notifications.viewResults', variant: 'primary' }],
  },
  {
    id: '2',
    type: 'warning',
    titleKey: 'notifications.parsingError',
    descriptionKey: 'notifications.parsingErrorDesc',
    timeKey: 'notifications.time.15mAgo',
    isRead: false,
    actions: [
      { labelKey: 'notifications.ignore', variant: 'secondary' },
      { labelKey: 'notifications.fix', variant: 'warning' },
    ],
  },
  {
    id: '3',
    type: 'info',
    titleKey: 'notifications.newBranch',
    descriptionKey: 'notifications.newBranchDesc',
    timeKey: 'notifications.time.1hAgo',
    isRead: true,
  },
];

const yesterdayNotifications: Notification[] = [
  {
    id: '4',
    type: 'system',
    titleKey: 'notifications.systemUpdate',
    descriptionKey: 'notifications.systemUpdateDesc',
    timeKey: '10:00 AM',
    isRead: true,
  },
];

const iconMap = {
  success: { icon: CheckCircle, bg: 'bg-emerald-100', text: 'text-emerald-600' },
  warning: { icon: AlertTriangle, bg: 'bg-amber-100', text: 'text-amber-600' },
  info: { icon: Store, bg: 'bg-blue-100', text: 'text-blue-600' },
  system: { icon: Monitor, bg: 'bg-slate-100', text: 'text-slate-600' },
};

const actionStyles = {
  primary: 'text-emerald-700 bg-emerald-50 hover:bg-emerald-100 border-emerald-100',
  secondary: 'text-slate-700 bg-white hover:bg-slate-50 border-slate-200 shadow-sm',
  warning: 'text-amber-700 bg-amber-50 hover:bg-amber-100 border-amber-100',
};

interface NotificationPanelProps {
  onClose: () => void;
}

export default function NotificationPanel({ onClose }: NotificationPanelProps) {
  const { t } = useTranslation();

  const renderNotification = (notif: Notification) => {
    const { icon: Icon, bg, text } = iconMap[notif.type];
    return (
      <div
        key={notif.id}
        className={cn(
          'group relative flex gap-4 px-5 py-4 hover:bg-white transition-colors cursor-pointer',
          notif.isRead ? 'bg-white/60' : 'bg-white'
        )}
      >
        {/* Left accent bar */}
        {!notif.isRead ? (
          <div className="absolute left-0 top-0 bottom-0 w-1 bg-primary" />
        ) : (
          <div className="absolute left-0 top-0 bottom-0 w-1 bg-transparent group-hover:bg-slate-200 transition-colors" />
        )}

        {/* Icon */}
        <div className={cn('mt-1 flex h-9 w-9 flex-none items-center justify-center rounded-full ring-4 ring-white', bg)}>
          <Icon className={cn('h-[18px] w-[18px]', text)} />
        </div>

        {/* Content */}
        <div className="flex-auto">
          <div className="flex items-baseline justify-between gap-x-4">
            <p className="text-sm font-semibold leading-6 text-slate-900">{t(notif.titleKey)}</p>
            <p className="flex-none text-xs text-slate-500">
              {notif.timeKey.startsWith('notifications.') ? t(notif.timeKey) : notif.timeKey}
            </p>
          </div>
          <p
            className="text-sm leading-5 text-slate-600"
            dangerouslySetInnerHTML={{ __html: t(notif.descriptionKey) }}
          />
          {notif.actions && (
            <div className="mt-3 flex gap-2">
              {notif.actions.map((action) => (
                <button
                  key={action.labelKey}
                  className={cn(
                    'text-xs font-medium px-3 py-1.5 rounded-md border transition-colors',
                    actionStyles[action.variant]
                  )}
                >
                  {t(action.labelKey)}
                </button>
              ))}
            </div>
          )}
        </div>

        {/* Unread dot */}
        {!notif.isRead && (
          <div className="flex-none self-start">
            <div className="h-2 w-2 rounded-full bg-primary mt-2" />
          </div>
        )}
      </div>
    );
  };

  return (
    <div className="absolute top-4 right-8 z-50 w-full max-w-md animate-in slide-in-from-top-4 fade-in duration-200">
      <div className="flex flex-col rounded-2xl border border-border bg-white shadow-2xl overflow-hidden ring-1 ring-black/5">
        {/* Header */}
        <div className="flex items-center justify-between border-b border-border px-5 py-4 bg-white/50 backdrop-blur-sm">
          <div className="flex items-center gap-2">
            <div className="bg-indigo-50 text-indigo-600 rounded-md p-1">
              <svg className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor">
                <path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z" />
              </svg>
            </div>
            <div>
              <h3 className="text-sm font-bold text-slate-900">{t('notifications.title')}</h3>
              <p className="text-[11px] text-slate-500 font-medium">{t('notifications.newCount', { count: 3 })}</p>
            </div>
          </div>
          <div className="flex gap-2">
            <button className="text-[11px] font-semibold text-primary hover:text-primary/80 hover:bg-primary/5 px-2.5 py-1.5 rounded-md transition-colors">
              {t('notifications.markAllRead')}
            </button>
            <button
              onClick={onClose}
              className="text-slate-400 hover:text-slate-600 p-1 hover:bg-slate-100 rounded-md transition-colors"
            >
              <X className="h-[18px] w-[18px]" />
            </button>
          </div>
        </div>

        {/* Scrollable body */}
        <div className="max-h-[600px] overflow-y-auto bg-slate-50/50">
          {/* Today */}
          <div className="px-5 py-2.5 sticky top-0 bg-slate-50/95 backdrop-blur-sm border-b border-border z-10">
            <span className="text-xs font-semibold text-slate-500 uppercase tracking-wider">
              {t('notifications.today')}
            </span>
          </div>
          <div className="divide-y divide-border">
            {todayNotifications.map(renderNotification)}
          </div>

          {/* Yesterday */}
          <div className="px-5 py-2.5 sticky top-0 bg-slate-50/95 backdrop-blur-sm border-b border-border border-t z-10">
            <span className="text-xs font-semibold text-slate-500 uppercase tracking-wider">
              {t('notifications.yesterday')}
            </span>
          </div>
          <div className="divide-y divide-border">
            {yesterdayNotifications.map(renderNotification)}
          </div>

          {/* View all */}
          <div className="p-3 text-center border-t border-border bg-slate-50">
            <button className="text-xs font-semibold text-primary hover:text-primary/80 transition-colors">
              {t('notifications.viewAll')}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}