/opt/canhelp/apps/api/src/routes
NameSizeModeActions
admin.ts950570644editdlrm
auto-match.ts74060644editdlrm
auto-response.ts81110644editdlrm
availability.ts72940644editdlrm
categories.ts18670644editdlrm
chat.ts93770644editdlrm
dashboard.ts51420644editdlrm
favorites.ts44410644editdlrm
fomo.ts68440644editdlrm
google.ts48720644editdlrm
health.ts12140644editdlrm
i18n.ts1670860644editdlrm
locations.ts17810644editdlrm
notifications.ts28620644editdlrm
offers.ts100470644editdlrm
payments.ts211670644editdlrm
plans.ts13520644editdlrm
portfolio.ts66580644editdlrm
price-list.ts144170644editdlrm
reports.ts20070644editdlrm
reviews.ts27830644editdlrm
skill-suggestions.ts10350644editdlrm
specialist-cards.ts186410644editdlrm
stats.ts10930644editdlrm
statuses.ts37310644editdlrm
support.ts84520644editdlrm
tasks.ts300180644editdlrm
uploads.ts15260644editdlrm
users.ts371570644editdlrm
Edit: /opt/canhelp/apps/api/src/routes/statuses.ts (3731B)
import { Hono } from 'hono' import { zValidator } from '@hono/zod-validator' import { z } from 'zod' import { eq, and } from 'drizzle-orm' import { db } from '../db.js' import { userStatuses, users, plans } from '@canhelp/db' import { requireAuth, type AuthVariables } from '../middleware/auth.js' const app = new Hono<{ Variables: AuthVariables }>() const STATUS_DURATION_HOURS = 8 // auto-expire after 8 hours /** Check plan permission for a status type */ async function canUseStatus(userId: string, statusType: string): Promise { const [user] = await db .select({ planId: users.planId, role: users.role }) .from(users) .where(eq(users.id, userId)) if (user?.role === 'admin') return true if (!user?.planId) return false const [plan] = await db.select().from(plans).where(eq(plans.id, user.planId)) if (!plan) return false if (statusType === 'canhelp_now') return !!plan.hasCanHelpNowStatus if (statusType === 'need_help') return !!plan.hasNeedHelpStatus return false } // GET /statuses/me — get current user's statuses app.get('/me', requireAuth, async (c) => { const user = c.get('user') const rows = await db .select() .from(userStatuses) .where(eq(userStatuses.userId, user.id)) // Auto-deactivate expired statuses const now = new Date() const result = rows.map((s) => { if (s.isActive && s.expiresAt && s.expiresAt < now) { return { ...s, isActive: false } } return s }) return c.json(result) }) // GET /statuses/user/:userId — get a user's active statuses (public) app.get('/user/:userId', async (c) => { const userId = c.req.param('userId') const now = new Date() const rows = await db .select({ statusType: userStatuses.statusType, isActive: userStatuses.isActive, activatedAt: userStatuses.activatedAt, expiresAt: userStatuses.expiresAt, }) .from(userStatuses) .where(and(eq(userStatuses.userId, userId), eq(userStatuses.isActive, true))) // Filter out expired const active = rows.filter((s) => !s.expiresAt || s.expiresAt > now) return c.json(active) }) // POST /statuses/toggle — activate or deactivate a status app.post( '/toggle', requireAuth, zValidator( 'json', z.object({ statusType: z.enum(['canhelp_now', 'need_help']), active: z.boolean(), }), ), async (c) => { const user = c.get('user') const { statusType, active } = c.req.valid('json') // Check plan permission if (active) { const allowed = await canUseStatus(user.id, statusType) if (!allowed) { return c.json({ error: `Your plan does not include the "${statusType}" status`, code: 'PLAN_FEATURE_RESTRICTED', }, 403) } } const now = new Date() const expiresAt = active ? new Date(now.getTime() + STATUS_DURATION_HOURS * 60 * 60 * 1000) : null // Upsert: find existing or create const [existing] = await db .select() .from(userStatuses) .where(and(eq(userStatuses.userId, user.id), eq(userStatuses.statusType, statusType))) if (existing) { const [updated] = await db .update(userStatuses) .set({ isActive: active, activatedAt: active ? now : existing.activatedAt, expiresAt, }) .where(eq(userStatuses.id, existing.id)) .returning() return c.json(updated) } const [created] = await db .insert(userStatuses) .values({ userId: user.id, statusType, isActive: active, activatedAt: active ? now : null, expiresAt, }) .returning() return c.json(created, 201) }, ) export default app