/opt/canhelp/apps/api/src/routes
Edit: /opt/canhelp/apps/api/src/routes/notifications.ts (2862B)
import { Hono } from 'hono'
import { eq, and, desc, count } from 'drizzle-orm'
import { db } from '../db.js'
import { notifications } from '@canhelp/db'
import { requireAuth, type AuthVariables } from '../middleware/auth.js'
const app = new Hono<{ Variables: AuthVariables }>()
// GET /notifications
app.get('/', requireAuth, async (c) => {
const user = c.get('user')
const limit = Math.min(Number(c.req.query('limit') || 50), 200)
const referenceId = c.req.query('referenceId')
const type = c.req.query('type')
const conditions: any[] = [eq(notifications.recipientId, user.id)]
if (referenceId) conditions.push(eq(notifications.referenceId, referenceId))
if (type) conditions.push(eq(notifications.type, type as any))
const rows = await db
.select()
.from(notifications)
.where(and(...conditions))
.orderBy(desc(notifications.createdAt))
.limit(limit)
return c.json(rows)
})
// GET /notifications/count — unread count
app.get('/count', requireAuth, async (c) => {
const user = c.get('user')
const [{ total }] = await db
.select({ total: count() })
.from(notifications)
.where(and(eq(notifications.recipientId, user.id), eq(notifications.isRead, false)))
return c.json({ count: total })
})
// PATCH /notifications/read-all
app.patch('/read-all', requireAuth, async (c) => {
const user = c.get('user')
await db
.update(notifications)
.set({ isRead: true })
.where(and(eq(notifications.recipientId, user.id), eq(notifications.isRead, false)))
return c.json({ ok: true })
})
// PATCH /notifications/:id/read
app.patch('/:id/read', requireAuth, async (c) => {
const user = c.get('user')
const [notif] = await db
.select()
.from(notifications)
.where(eq(notifications.id, c.req.param('id')))
if (!notif) return c.json({ error: 'Not found' }, 404)
if (notif.recipientId !== user.id) return c.json({ error: 'Forbidden' }, 403)
const [updated] = await db
.update(notifications)
.set({ isRead: true })
.where(eq(notifications.id, notif.id))
.returning()
return c.json(updated)
})
// DELETE /notifications — clear all for current user
app.delete('/', requireAuth, async (c) => {
const user = c.get('user')
await db.delete(notifications).where(eq(notifications.recipientId, user.id))
return c.json({ ok: true })
})
// DELETE /notifications/:id — dismiss single notification
app.delete('/:id', requireAuth, async (c) => {
const user = c.get('user')
const [notif] = await db
.select()
.from(notifications)
.where(eq(notifications.id, c.req.param('id')))
if (!notif) return c.json({ error: 'Not found' }, 404)
if (notif.recipientId !== user.id) return c.json({ error: 'Forbidden' }, 403)
await db.delete(notifications).where(eq(notifications.id, notif.id))
return c.json({ ok: true })
})
export default app