Finalize metrics verification and backlog updates
This commit is contained in:
@@ -86,6 +86,7 @@ export type LeadFunnelOutreach = {
|
||||
sendStatus?: OutreachSendStatus | null;
|
||||
responseStatus?: OutreachResponseStatus | null;
|
||||
salesStatus?: OutreachSalesStatus | null;
|
||||
doNotContactUntil?: number | null;
|
||||
};
|
||||
|
||||
export type LeadFunnelInput = {
|
||||
@@ -103,6 +104,7 @@ export type LeadFunnelInput = {
|
||||
contactPerson?: string | null;
|
||||
websiteDomain?: string | null;
|
||||
outreach?: LeadFunnelOutreach | null;
|
||||
now?: number;
|
||||
};
|
||||
|
||||
export type LeadFunnelCard = {
|
||||
@@ -303,6 +305,14 @@ function getLeadNextAction(lead: LeadFunnelInput): string {
|
||||
const stageId = getLeadFunnelStageId(lead);
|
||||
|
||||
if (stageId === "deferred") {
|
||||
if (
|
||||
lead.outreach?.salesStatus === "do_not_pursue" &&
|
||||
typeof lead.outreach.doNotContactUntil === "number" &&
|
||||
(lead.now ?? Date.now()) >= lead.outreach.doNotContactUntil
|
||||
) {
|
||||
return "Erneut prüfen";
|
||||
}
|
||||
|
||||
return "Zurückstellung prüfen";
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,12 @@ export type AuditRybbitSummary = {
|
||||
deviceTypes: string[];
|
||||
};
|
||||
|
||||
export type CampaignRybbitSummary = {
|
||||
auditOpens: number;
|
||||
ctaClicks: number;
|
||||
outboundClicks: number;
|
||||
};
|
||||
|
||||
type FetchLike = (
|
||||
input: string | URL,
|
||||
init?: RequestInit,
|
||||
@@ -117,6 +123,23 @@ export function summarizeAuditRybbitEvents(
|
||||
};
|
||||
}
|
||||
|
||||
export function summarizeCampaignRybbitEvents(
|
||||
events: RybbitEvent[],
|
||||
): CampaignRybbitSummary {
|
||||
const auditEvents = events.filter((event) => eventPath(event).startsWith("/audit/"));
|
||||
|
||||
return {
|
||||
auditOpens: auditEvents.filter((event) => event.type === "pageview").length,
|
||||
ctaClicks: auditEvents.filter((event) => {
|
||||
return event.type === "custom_event" && eventName(event) === "audit_cta_click";
|
||||
}).length,
|
||||
outboundClicks: auditEvents.filter((event) => {
|
||||
return event.type === "outbound_link" ||
|
||||
eventName(event) === "audit_website_link_click";
|
||||
}).length,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeEventsPayload(payload: unknown): RybbitEvent[] {
|
||||
if (Array.isArray(payload)) {
|
||||
return payload.filter((event): event is RybbitEvent => typeof event === "object" && event !== null);
|
||||
@@ -193,3 +216,58 @@ export async function fetchRybbitAuditAnalytics(input: {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchRybbitCampaignAnalytics(input: {
|
||||
apiUrl?: string;
|
||||
apiKey?: string;
|
||||
siteId?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
fetchImpl?: FetchLike;
|
||||
}) {
|
||||
if (!input.apiUrl || !input.apiKey || !input.siteId) {
|
||||
return {
|
||||
ok: false as const,
|
||||
error: "Rybbit ist nicht vollständig konfiguriert.",
|
||||
data: summarizeCampaignRybbitEvents([]),
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await (input.fetchImpl ?? fetch)(
|
||||
buildRybbitEventsUrl({
|
||||
apiUrl: input.apiUrl,
|
||||
siteId: input.siteId,
|
||||
startDate: input.startDate,
|
||||
endDate: input.endDate,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${input.apiKey}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
return {
|
||||
ok: false as const,
|
||||
error: `Rybbit API Fehler ${response.status}: ${body.slice(0, 160)}`,
|
||||
data: summarizeCampaignRybbitEvents([]),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true as const,
|
||||
data: summarizeCampaignRybbitEvents(
|
||||
normalizeEventsPayload(await response.json()),
|
||||
),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false as const,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
data: summarizeCampaignRybbitEvents([]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user