90 lines
2.5 KiB
TypeScript
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" };
|
|
}
|