Files
pitchfast/lib/outreach-follow-up.ts

90 lines
2.5 KiB
TypeScript

import type {
OutreachResponseStatus,
OutreachSalesStatus,
OutreachSendStatus,
} from "./dashboard-model";
export const FOLLOW_UP_DUE_DELAY_MS = 7 * 24 * 60 * 60 * 1000;
export const DO_NOT_CONTACT_RECHECK_MS = 365 * 24 * 60 * 60 * 1000;
export type FollowUpPromptState = "not_ready" | "pending" | "due" | "suppressed";
export const manualSalesStatusLabels: Record<OutreachSalesStatus, string> = {
follow_up_planned: "Follow-up geplant",
follow_up_sent: "Follow-up gesendet",
reply_received: "Antwort erhalten",
not_interested: "Kein Interesse",
later: "Später wieder melden",
meeting_scheduled: "Gespräch vereinbart",
proposal_requested: "Angebot angefragt",
proposal_sent: "Angebot gesendet",
won: "Auftrag gewonnen",
lost: "Auftrag verloren",
do_not_pursue: "Nicht weiter verfolgen",
};
const suppressingSalesStatuses = new Set<OutreachSalesStatus>([
"reply_received",
"not_interested",
"do_not_pursue",
"follow_up_sent",
]);
const suppressingResponseStatuses = new Set<OutreachResponseStatus>([
"manual_reply_recorded",
"no_interest",
]);
export function getManualSalesStatusLabel(status: OutreachSalesStatus) {
return manualSalesStatusLabels[status];
}
export function shouldCreateFollowUpDraftAfterSend(input: {
existingFollowUpOutreachCount: number;
followUpDraft?: string | null;
salesStatus: OutreachSalesStatus;
sendStatus: OutreachSendStatus;
}) {
return (
input.sendStatus === "sent" &&
input.salesStatus === "follow_up_planned" &&
input.existingFollowUpOutreachCount === 0 &&
Boolean(input.followUpDraft?.trim())
);
}
export function getFollowUpPromptState(input: {
followUpDueAt?: number | null;
responseStatus: OutreachResponseStatus;
salesStatus: OutreachSalesStatus;
now: number;
}): FollowUpPromptState {
if (
suppressingSalesStatuses.has(input.salesStatus) ||
suppressingResponseStatuses.has(input.responseStatus)
) {
return "suppressed";
}
if (typeof input.followUpDueAt !== "number") {
return "not_ready";
}
return input.now >= input.followUpDueAt ? "due" : "pending";
}
export function getDoNotContactRecheckState(input: {
doNotContactUntil?: number | null;
now: number;
}) {
if (typeof input.doNotContactUntil !== "number") {
return { status: "none" as const, label: "Offen" };
}
if (input.now >= input.doNotContactUntil) {
return { status: "recheck" as const, label: "Erneut prüfen" };
}
return { status: "blocked" as const, label: "Nicht erneut kontaktieren" };
}