Feature: Add unread message notifications to admin badge

- Add isRead boolean field to Message model (default: false)
- Create migration to update database schema
- Update admin notifications to count unread messages
- Display unread message count in notification badge tooltip
- Admins now see all notifications: pending orders, design approvals, photo requests, unread messages
- Color-coded tooltip: orange (orders), blue (designs), clay (photos), pink (messages)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-19 07:54:03 +01:00
co-authored by Claude Haiku 4.5
parent 3e90928986
commit a1c463fb49
4 changed files with 18 additions and 2 deletions
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "isRead" BOOLEAN NOT NULL DEFAULT false;
+1
View File
@@ -175,6 +175,7 @@ model Message {
proof DesignProof @relation(fields: [proofId], references: [id], onDelete: Cascade) proof DesignProof @relation(fields: [proofId], references: [id], onDelete: Cascade)
sender String // "ADMIN" | "CUSTOMER" sender String // "ADMIN" | "CUSTOMER"
body String body String
isRead Boolean @default(false)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
} }
+7 -2
View File
@@ -13,6 +13,7 @@ export default async function AdminNotifications() {
pendingOrders, pendingOrders,
designApprovalsInReview, designApprovalsInReview,
photoRequests, photoRequests,
unreadMessages,
] = await Promise.all([ ] = await Promise.all([
prisma.order.count({ prisma.order.count({
where: { where: {
@@ -26,9 +27,12 @@ export default async function AdminNotifications() {
prisma.customRequest.count({ prisma.customRequest.count({
where: { status: 'PENDING' }, where: { status: 'PENDING' },
}), }),
prisma.message.count({
where: { isRead: false },
}),
]); ]);
const totalNotifications = pendingOrders + designApprovalsInReview + photoRequests; const totalNotifications = pendingOrders + designApprovalsInReview + photoRequests + unreadMessages;
return ( return (
<AdminNotificationsBadge <AdminNotificationsBadge
@@ -36,10 +40,11 @@ export default async function AdminNotifications() {
pendingOrders={pendingOrders} pendingOrders={pendingOrders}
designApprovals={designApprovalsInReview} designApprovals={designApprovalsInReview}
photoRequests={photoRequests} photoRequests={photoRequests}
unreadMessages={unreadMessages}
/> />
); );
} catch (err) { } catch (err) {
console.error('Error fetching admin notifications:', err); console.error('Error fetching admin notifications:', err);
return <AdminNotificationsBadge total={0} pendingOrders={0} designApprovals={0} photoRequests={0} />; return <AdminNotificationsBadge total={0} pendingOrders={0} designApprovals={0} photoRequests={0} unreadMessages={0} />;
} }
} }
@@ -7,6 +7,7 @@ interface AdminNotificationsBadgeProps {
pendingOrders: number; pendingOrders: number;
designApprovals: number; designApprovals: number;
photoRequests: number; photoRequests: number;
unreadMessages: number;
} }
export default function AdminNotificationsBadge({ export default function AdminNotificationsBadge({
@@ -14,6 +15,7 @@ export default function AdminNotificationsBadge({
pendingOrders, pendingOrders,
designApprovals, designApprovals,
photoRequests, photoRequests,
unreadMessages,
}: AdminNotificationsBadgeProps) { }: AdminNotificationsBadgeProps) {
const [showTooltip, setShowTooltip] = useState(false); const [showTooltip, setShowTooltip] = useState(false);
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
@@ -61,6 +63,12 @@ export default function AdminNotificationsBadge({
<span className="font-bold text-clay">{photoRequests}</span> <span className="font-bold text-clay">{photoRequests}</span>
</div> </div>
)} )}
{unreadMessages > 0 && (
<div className="flex items-center justify-between py-2 px-3 bg-surface rounded">
<span className="text-muted">Unread messages</span>
<span className="font-bold text-splash-pink">{unreadMessages}</span>
</div>
)}
</div> </div>
)} )}
</div> </div>