diff --git a/server.ts b/server.ts index 98f8a63..d0dda6b 100644 --- a/server.ts +++ b/server.ts @@ -54,6 +54,43 @@ async function logError(context: string, error: any, additionalData?: any) { // TEAMS WEBHOOK NOTIFICATION (Power Automate) // ============================================================================ +function buildAdaptiveCard(jobData: any, jobFolderLink: string) { + const jobName = jobData.Job_Name || ''; + const jobNumber = jobData.Job_Number || ''; + const jobAddress = jobData.Job_Address || ''; + const companyClient = jobData.Company_Client || ''; + const jobDivision = jobData.Job_Division || ''; + const jobType = jobData.Job_Type || ''; + const contactPerson = jobData.Contact_Person || ''; + const phoneNumber = jobData.Phone_Number || ''; + + // Valid Adaptive Card (Teams flowbot expects type: AdaptiveCard) + return { + type: 'AdaptiveCard', + $schema: 'http://adaptivecards.io/schemas/adaptive-card.json', + version: '1.5', + body: [ + { type: 'TextBlock', text: 'New Job!', weight: 'Bolder', size: 'Large' }, + { type: 'TextBlock', text: `${jobNumber} - ${jobName}`, wrap: true }, + { + type: 'FactSet', + facts: [ + { title: 'Number', value: jobNumber || 'N/A' }, + { title: 'Name', value: jobName || 'N/A' }, + { title: 'Address', value: jobAddress || 'N/A' }, + { title: 'Client', value: companyClient || 'N/A' }, + { title: 'Division', value: jobDivision || 'N/A' }, + { title: 'Type', value: jobType || 'N/A' }, + { title: 'Contact', value: (contactPerson && phoneNumber) ? `${contactPerson} - ${phoneNumber}` : (contactPerson || 'N/A') } + ] + } + ], + actions: jobFolderLink ? [ + { type: 'Action.OpenUrl', title: 'Open Folder', url: jobFolderLink } + ] : [] + }; +} + async function notifyTeamsChannel(jobData: any, jobFolderLink: string) { const webhook = process.env.POWER_AUTOMATE_WEBHOOK_URL || process.env.TEAMS_WEBHOOK_URL; @@ -73,8 +110,10 @@ async function notifyTeamsChannel(jobData: any, jobFolderLink: string) { const contactPerson = jobData.Contact_Person || ''; const phoneNumber = jobData.Phone_Number || ''; - // Build payload for Power Automate + // Build Adaptive Card and payload for Power Automate + const adaptiveCard = buildAdaptiveCard(jobData, jobFolderLink); const payload = { + // raw fields, in case the flow maps them directly jobNumber, jobName, jobAddress, @@ -83,9 +122,14 @@ async function notifyTeamsChannel(jobData: any, jobFolderLink: string) { jobType, contactPerson, phoneNumber, - jobFolderLink + jobFolderLink, + // Provide card in common parameter names used by PA templates + card: JSON.stringify(adaptiveCard), + adaptiveCard }; + console.log(`[Power Automate] Sending webhook for Job ${jobNumber}:`, JSON.stringify(payload, null, 2)); + const response = await fetch(webhook, { method: 'POST', headers: { @@ -96,12 +140,13 @@ async function notifyTeamsChannel(jobData: any, jobFolderLink: string) { if (!response.ok) { const text = await response.text(); - console.warn(`⚠️ Power Automate notification failed: ${response.status} ${text}`); + console.warn(`⚠️ Power Automate notification failed: ${response.status} ${response.statusText}`); + console.warn(` Response: ${text}`); } else { - console.log(`✓ Power Automate notification sent for Job ${jobNumber}`); + console.log(`✓ Power Automate notification sent for Job ${jobNumber} (${response.status})`); } } catch (error: any) { - console.error('⚠️ Failed to send Power Automate notification:', error); + console.error('⚠️ Failed to send Power Automate notification:', error.message); // Don't fail the job creation if notification fails } }