149 lines
4.4 KiB
TypeScript
149 lines
4.4 KiB
TypeScript
'use client';
|
||
|
||
import { useEffect, useState } from 'react';
|
||
import { loadComponent } from '@/lib/material-components';
|
||
import { useOptimizedFetch } from '@/hooks/useOptimizedFetch';
|
||
|
||
export default function NotificationsPage() {
|
||
const [componentsLoaded, setComponentsLoaded] = useState(false);
|
||
const [filter, setFilter] = useState<'unread'>('unread');
|
||
|
||
useEffect(() => {
|
||
Promise.all([
|
||
loadComponent('elevated-card'),
|
||
loadComponent('list'),
|
||
loadComponent('list-item'),
|
||
loadComponent('icon'),
|
||
loadComponent('chip-set'),
|
||
loadComponent('assist-chip'),
|
||
]).then(() => {
|
||
setComponentsLoaded(true);
|
||
}).catch((err) => {
|
||
console.error('Error loading components:', err);
|
||
setComponentsLoaded(true);
|
||
});
|
||
}, []);
|
||
|
||
const { data: notificationsData, loading, refetch } = useOptimizedFetch({
|
||
url: '/notifications/',
|
||
cacheKey: 'notifications_list',
|
||
cacheTTL: 1 * 60 * 1000, // 1 минута
|
||
});
|
||
|
||
if (!componentsLoaded) {
|
||
return (
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
height: '50vh'
|
||
}}>
|
||
<div>Загрузка...</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const notifications = notificationsData?.results || [];
|
||
const filteredNotifications = notifications.filter((n: any) => !n.is_read);
|
||
|
||
return (
|
||
<div>
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: '24px',
|
||
flexWrap: 'wrap',
|
||
gap: '16px'
|
||
}}>
|
||
<h1 style={{
|
||
fontSize: '28px',
|
||
fontWeight: '400',
|
||
margin: 0,
|
||
color: 'var(--md-sys-color-on-surface)'
|
||
}}>
|
||
Уведомления
|
||
</h1>
|
||
<md-filled-button onClick={() => refetch()}>
|
||
Обновить
|
||
</md-filled-button>
|
||
</div>
|
||
|
||
{/* Фильтры */}
|
||
<div style={{ marginBottom: '24px' }}>
|
||
<md-chip-set>
|
||
<md-assist-chip
|
||
label="Непрочитанные"
|
||
selected={filter === 'unread'}
|
||
onClick={() => setFilter('unread')}
|
||
/>
|
||
</md-chip-set>
|
||
</div>
|
||
|
||
{loading ? (
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
padding: '40px'
|
||
}}>
|
||
<div>Загрузка уведомлений...</div>
|
||
</div>
|
||
) : filteredNotifications.length === 0 ? (
|
||
<md-elevated-card style={{
|
||
padding: '40px',
|
||
borderRadius: '20px',
|
||
textAlign: 'center'
|
||
}}>
|
||
<md-icon style={{
|
||
fontSize: '64px',
|
||
color: 'var(--md-sys-color-on-surface-variant)',
|
||
marginBottom: '16px'
|
||
}}>
|
||
notifications
|
||
</md-icon>
|
||
<p style={{
|
||
fontSize: '16px',
|
||
color: 'var(--md-sys-color-on-surface-variant)'
|
||
}}>
|
||
Нет непрочитанных уведомлений
|
||
</p>
|
||
</md-elevated-card>
|
||
) : (
|
||
<md-list style={{
|
||
background: 'var(--md-sys-color-surface)',
|
||
borderRadius: '20px',
|
||
padding: '8px'
|
||
}}>
|
||
{filteredNotifications.map((notification: any) => (
|
||
<md-list-item
|
||
key={notification.id}
|
||
headline={notification.title || 'Уведомление'}
|
||
supportingText={notification.message || ''}
|
||
style={{
|
||
borderRadius: '12px',
|
||
marginBottom: '4px',
|
||
opacity: notification.is_read ? 0.7 : 1,
|
||
background: notification.is_read
|
||
? 'transparent'
|
||
: 'var(--md-sys-color-primary-container)',
|
||
}}
|
||
>
|
||
<md-icon slot="start">
|
||
{notification.type === 'info' ? 'info' : 'notifications'}
|
||
</md-icon>
|
||
{notification.created_at && (
|
||
<span slot="end" style={{
|
||
fontSize: '12px',
|
||
color: 'var(--md-sys-color-on-surface-variant)'
|
||
}}>
|
||
{new Date(notification.created_at).toLocaleDateString('ru-RU')}
|
||
</span>
|
||
)}
|
||
</md-list-item>
|
||
))}
|
||
</md-list>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|