/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/locations.ts (1781B)
import { Hono } from 'hono' import { eq, asc } from 'drizzle-orm' import { db } from '../db.js' import { locations } from '@canhelp/db' import { redis } from '../redis.js' const CACHE_KEY = 'locations:tree:v2' const CACHE_TTL = 600 const app = new Hono() function rowToLocation(row: typeof locations.$inferSelect) { return { id: row.id, slug: row.slug, names: { el: row.nameEl, en: row.nameEn, ru: row.nameRu, uk: row.nameUk ?? row.nameRu }, parentId: row.parentId, order: row.order, isActive: row.isActive, } } function buildTree(rows: typeof locations.$inferSelect[]) { const map: Record = {} const roots: any[] = [] for (const row of rows) { map[row.id] = { ...rowToLocation(row), children: [] } } for (const row of rows) { if (row.parentId && map[row.parentId]) { map[row.parentId].children.push(map[row.id]) } else { roots.push(map[row.id]) } } return roots } // GET /locations — tree of active locations app.get('/', async (c) => { const cached = await redis.get(CACHE_KEY).catch(() => null) if (cached) return c.json(JSON.parse(cached)) const rows = await db .select() .from(locations) .where(eq(locations.isActive, true)) .orderBy(asc(locations.order), asc(locations.nameEl)) const tree = buildTree(rows) await redis.set(CACHE_KEY, JSON.stringify(tree), 'EX', CACHE_TTL).catch(() => {}) return c.json(tree) }) // GET /locations/flat — flat list for dropdowns app.get('/flat', async (c) => { const rows = await db .select() .from(locations) .where(eq(locations.isActive, true)) .orderBy(asc(locations.order), asc(locations.nameEl)) return c.json(rows.map(rowToLocation)) }) export { buildTree, rowToLocation } export default app