diff --git a/src/routes/integrations.js b/src/routes/integrations.js index a2c85b9..3bd0ef0 100644 --- a/src/routes/integrations.js +++ b/src/routes/integrations.js @@ -120,7 +120,7 @@ export async function integrationRoutes(app) { if (!creds.bearer_token) return reply.status(400).send({ error: 'Workforce bearer token not configured' }) const baseUrl = creds.base_url || 'https://my.tanda.co' - // /api/v2/locations may be locked by billing tier — derive from teams instead + // /api/v2/locations list may be billing-locked — get unique IDs from teams then fetch each individually const teams = [] let page = 1 while (true) { @@ -140,20 +140,24 @@ export async function integrationRoutes(app) { page++ } - // Group team names by location_id - const locMap = {} - for (const t of teams) { - if (!t.location_id) continue - const id = String(t.location_id) - if (!locMap[id]) locMap[id] = [] - locMap[id].push(t.name) - } + const locationIds = [...new Set(teams.map(t => t.location_id).filter(Boolean).map(String))] - return Object.entries(locMap).map(([id, teamNames]) => ({ - id, - name: `Location ${id}`, - team_names: teamNames.sort(), + // Fetch each location individually in parallel + const locations = await Promise.all(locationIds.map(async id => { + try { + const res = await fetch(`${baseUrl}/api/v2/locations/${id}`, { + headers: { Authorization: `Bearer ${creds.bearer_token}` }, + signal: AbortSignal.timeout(8000), + }) + if (!res.ok) return { id, name: `Location ${id}`, short_name: null } + const loc = await res.json() + return { id, name: loc.name ?? `Location ${id}`, short_name: loc.short_name ?? null } + } catch { + return { id, name: `Location ${id}`, short_name: null } + } })) + + return locations.sort((a, b) => a.name.localeCompare(b.name)) }) app.post('/integrations/newbook/sync-rooms', { preHandler: requireAdmin }, async (req, reply) => {