mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
feat: add call lookup endpoint with lead matching + AI enrichment, token passthrough on platform service
This commit is contained in:
@@ -13,14 +13,20 @@ export class PlatformGraphqlService {
|
||||
this.apiKey = config.get<string>('platform.apiKey')!;
|
||||
}
|
||||
|
||||
// Server-to-server query using API key
|
||||
private async query<T>(query: string, variables?: Record<string, any>): Promise<T> {
|
||||
return this.queryWithAuth<T>(query, variables, `Bearer ${this.apiKey}`);
|
||||
}
|
||||
|
||||
// Query using a passed-through auth header (user JWT)
|
||||
private async queryWithAuth<T>(query: string, variables: Record<string, any> | undefined, authHeader: string): Promise<T> {
|
||||
const response = await axios.post(
|
||||
this.graphqlUrl,
|
||||
{ query, variables },
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.apiKey}`,
|
||||
'Authorization': authHeader,
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -114,6 +120,80 @@ export class PlatformGraphqlService {
|
||||
return data.createLeadActivity;
|
||||
}
|
||||
|
||||
// --- Token passthrough versions (for user-driven requests) ---
|
||||
|
||||
async findLeadByPhoneWithToken(phone: string, authHeader: string): Promise<LeadNode | null> {
|
||||
const normalizedPhone = phone.replace(/\D/g, '');
|
||||
const last10 = normalizedPhone.slice(-10);
|
||||
|
||||
const data = await this.queryWithAuth<{ leads: { edges: { node: LeadNode }[] } }>(
|
||||
`query FindLeads($first: Int) {
|
||||
leads(first: $first, orderBy: [{ createdAt: DescNullsLast }]) {
|
||||
edges {
|
||||
node {
|
||||
id createdAt
|
||||
contactName { firstName lastName }
|
||||
contactPhone { number callingCode }
|
||||
contactEmail { address }
|
||||
leadSource leadStatus interestedService
|
||||
assignedAgent campaignId adId
|
||||
contactAttempts spamScore isSpam
|
||||
aiSummary aiSuggestedAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ first: 200 },
|
||||
authHeader,
|
||||
);
|
||||
|
||||
// Client-side phone matching
|
||||
return data.leads.edges.find(edge => {
|
||||
const phones = edge.node.contactPhone ?? [];
|
||||
if (Array.isArray(phones)) {
|
||||
return phones.some((p: any) => {
|
||||
const num = (p.number ?? p.primaryPhoneNumber ?? '').replace(/\D/g, '');
|
||||
return num.endsWith(last10) || last10.endsWith(num);
|
||||
});
|
||||
}
|
||||
// Handle single phone object
|
||||
const num = ((phones as any).primaryPhoneNumber ?? (phones as any).number ?? '').replace(/\D/g, '');
|
||||
return num.endsWith(last10) || last10.endsWith(num);
|
||||
})?.node ?? null;
|
||||
}
|
||||
|
||||
async getLeadActivitiesWithToken(leadId: string, authHeader: string, limit = 5): Promise<LeadActivityNode[]> {
|
||||
const data = await this.queryWithAuth<{ leadActivities: { edges: { node: LeadActivityNode }[] } }>(
|
||||
`query GetLeadActivities($filter: LeadActivityFilterInput, $first: Int) {
|
||||
leadActivities(filter: $filter, first: $first, orderBy: [{ occurredAt: DescNullsLast }]) {
|
||||
edges {
|
||||
node {
|
||||
id activityType summary occurredAt performedBy channel
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ filter: { leadId: { eq: leadId } }, first: limit },
|
||||
authHeader,
|
||||
);
|
||||
return data.leadActivities.edges.map(e => e.node);
|
||||
}
|
||||
|
||||
async updateLeadWithToken(id: string, input: UpdateLeadInput, authHeader: string): Promise<LeadNode> {
|
||||
const data = await this.queryWithAuth<{ updateLead: LeadNode }>(
|
||||
`mutation UpdateLead($id: ID!, $data: LeadUpdateInput!) {
|
||||
updateLead(id: $id, data: $data) {
|
||||
id leadStatus aiSummary aiSuggestedAction
|
||||
}
|
||||
}`,
|
||||
{ id, data: input },
|
||||
authHeader,
|
||||
);
|
||||
return data.updateLead;
|
||||
}
|
||||
|
||||
// --- Server-to-server versions (for webhooks, background jobs) ---
|
||||
|
||||
async getLeadActivities(leadId: string, limit = 3): Promise<LeadActivityNode[]> {
|
||||
const data = await this.query<{ leadActivities: { edges: { node: LeadActivityNode }[] } }>(
|
||||
`query GetLeadActivities($filter: LeadActivityFilterInput, $first: Int) {
|
||||
|
||||
Reference in New Issue
Block a user