import { InlineKeyboard } from 'grammy'; import { payloadClient, type TenantDoc } from '../payload/client.js'; import { createLogger } from '../utils/logger.js'; const log = createLogger('Keyboards'); // Tenant cache with 5-minute TTL let tenantCache: TenantDoc[] | null = null; let cacheExpiresAt = 0; const CACHE_TTL = 5 * 60 * 1000; // 5 minutes async function loadTenants(): Promise { const now = Date.now(); // Return valid cache if (tenantCache && cacheExpiresAt > now) { return tenantCache; } try { const tenants = await payloadClient.listTenants(); tenantCache = tenants; cacheExpiresAt = now + CACHE_TTL; log.info(`Loaded ${tenants.length} tenants from API`); return tenants; } catch (error) { // Stale cache fallback: if API fails but we have old data, return it if (tenantCache) { log.warn('API failed, returning stale tenant cache', error); return tenantCache; } log.error('Failed to load tenants and no cache available', error); throw error; } } export async function buildTenantKeyboard(): Promise { const tenants = await loadTenants(); const keyboard = new InlineKeyboard(); for (let i = 0; i < tenants.length; i++) { const tenant = tenants[i]; keyboard.text(tenant.name, `tenant:${tenant.id}`); // 2 buttons per row if (i % 2 === 1 && i < tenants.length - 1) { keyboard.row(); } } return keyboard; } export async function getTenantName(tenantId: number): Promise { try { const tenants = await loadTenants(); const tenant = tenants.find((t) => t.id === tenantId); return tenant?.name ?? `Tenant ${tenantId}`; } catch { return `Tenant ${tenantId}`; } }