feat: refine admin forms, attendance and finance workflows
Squash merge PR #23. Included changes: - complete occupancy check-in required fields/default payload - improve responsive admin management pages - fix attendance edge cases and attendance period config - refine wallet/finance-related workflow handling Checks: - npm run typecheck -w apps/admin - npm run typecheck -w apps/server
This commit is contained in:
@@ -34,16 +34,20 @@ const NotificationBell: React.FC = () => {
|
||||
|
||||
const fetchNotifications = async () => {
|
||||
try {
|
||||
const data = await api.get('/notifications?limit=20') as unknown as NotificationItem[];
|
||||
const data = (await api.get('/notifications?limit=20')) as unknown as NotificationItem[];
|
||||
setNotifications(data);
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
|
||||
const fetchUnread = async () => {
|
||||
try {
|
||||
const data = await api.get('/notifications/unread-count') as unknown as { count: number };
|
||||
const data = (await api.get('/notifications/unread-count')) as unknown as { count: number };
|
||||
setUnreadCount(data.count);
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
const openRef = useRef(open);
|
||||
openRef.current = open;
|
||||
@@ -60,7 +64,9 @@ const NotificationBell: React.FC = () => {
|
||||
JSON.parse(event.data);
|
||||
setUnreadCount((c) => c + 1);
|
||||
if (openRef.current) fetchNotifications();
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
es.onerror = () => {
|
||||
es.close();
|
||||
@@ -84,7 +90,9 @@ const NotificationBell: React.FC = () => {
|
||||
try {
|
||||
await api.put(`/notifications/${item.id}/read`);
|
||||
setUnreadCount((c) => Math.max(0, c - 1));
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
setOpen(false);
|
||||
if (item.link) navigate(item.link);
|
||||
@@ -94,10 +102,10 @@ const NotificationBell: React.FC = () => {
|
||||
try {
|
||||
await api.put('/notifications/read-all');
|
||||
setUnreadCount(0);
|
||||
setNotifications((prev) =>
|
||||
prev.map((n) => ({ ...n, isRead: true })),
|
||||
);
|
||||
} catch { /* ignore */ }
|
||||
setNotifications((prev) => prev.map((n) => ({ ...n, isRead: true })));
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
};
|
||||
|
||||
const content = (
|
||||
@@ -148,18 +156,13 @@ const NotificationBell: React.FC = () => {
|
||||
)
|
||||
}
|
||||
title={
|
||||
<Typography.Text
|
||||
strong={!item.isRead}
|
||||
style={{ fontSize: 14 }}
|
||||
>
|
||||
[{notificationTypeLabels[item.type] || item.type}] {formatNotificationText(item.title)}
|
||||
<Typography.Text strong={!item.isRead} style={{ fontSize: 14 }}>
|
||||
[{notificationTypeLabels[item.type] || item.type}]{' '}
|
||||
{formatNotificationText(item.title)}
|
||||
</Typography.Text>
|
||||
}
|
||||
description={
|
||||
<Typography.Text
|
||||
type="secondary"
|
||||
style={{ fontSize: 12 }}
|
||||
>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{timeAgo(item.createdAt)}
|
||||
</Typography.Text>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user