Skip to content

Commit

Permalink
Merge pull request #162 from cabcookie:improve-person-mention
Browse files Browse the repository at this point in the history
fix: small issues in CRM hygiene
  • Loading branch information
cabcookie authored Aug 5, 2024
2 parents 0e60430 + f2d94f5 commit aaaeeef
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 22 deletions.
2 changes: 1 addition & 1 deletion api/useCrmProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
const client = generateClient<Schema>();

export const STAGES_PROBABILITY = [
{ stage: "Prospect", probability: 0 },
{ stage: "Prospect", probability: 10 },
{ stage: "Qualified", probability: 20 },
{ stage: "Technical Validation", probability: 40 },
{ stage: "Business Validation", probability: 60 },
Expand Down
9 changes: 9 additions & 0 deletions components/crm/group-projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
get,
map,
size,
some,
sortBy,
sum,
uniq,
Expand All @@ -16,6 +17,8 @@ import { FC } from "react";
import DefaultAccordionItem from "../ui-elements/accordion/DefaultAccordionItem";
import CrmProjectDetails from "../ui-elements/crm-project-details/crm-project-details";
import { Accordion } from "../ui/accordion";
import HygieneIssueBadge from "./hygiene-issue-badge";
import { hasHygieneIssues } from "./pipeline-hygiene";

type CrmProjectForGrouping = Pick<CrmProject, "accountName" | "partnerName">;
type ValidAccountPropertyNames = keyof CrmProjectForGrouping;
Expand Down Expand Up @@ -52,6 +55,12 @@ const GroupCrmProjects: FC<GroupCrmProjectsProps> = ({
<DefaultAccordionItem
value={`${propertyName}-${company}`}
triggerTitle={company}
badge={
flow(
getCrmProjectsByAccount(propertyName, company),
some(hasHygieneIssues)
)(crmProjects) && <HygieneIssueBadge />
}
triggerSubTitle={[
`${flow(
getCrmProjectsByAccount(propertyName, company),
Expand Down
11 changes: 11 additions & 0 deletions components/crm/hygiene-issue-badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Circle } from "lucide-react";
import { Badge } from "../ui/badge";

const HygieneIssueBadge = () => (
<>
<Circle className="mt-[0.2rem] w-4 min-w-4 h-4 md:hidden bg-orange-400 rounded-full text-destructive-foreground" />
<Badge className="hidden md:block bg-orange-400">Hygiene</Badge>
</>
);

export default HygieneIssueBadge;
4 changes: 2 additions & 2 deletions components/crm/next-steps.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useCrmProject from "@/api/useCrmProject";
import { CrmProject } from "@/api/useCrmProjects";
import { format } from "date-fns";
import { Edit, LinkIcon, Loader2 } from "lucide-react";
import { ClipboardCopy, Edit, Loader2 } from "lucide-react";
import { FC, useEffect, useState } from "react";
import { Button } from "../ui/button";
import { Textarea } from "../ui/textarea";
Expand Down Expand Up @@ -64,7 +64,7 @@ const NextStep: FC<NextStepProps> = ({ crmProject }) => {
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<LinkIcon
<ClipboardCopy
className="w-4 h-4 text-muted-foreground hover:text-primary"
onClick={handleCopyToClipBoard}
/>
Expand Down
23 changes: 16 additions & 7 deletions components/crm/pipeline-hygiene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,52 +53,61 @@ const notTooOld = (days: number) => (date: Date) =>
const hasCompliantNextStepDate = (crm: CrmProject) =>
flow(getNextStepDateElements, getDate, notTooOld(30))(crm);

const isOpen = (crm: CrmProject) =>
!(["Closed Lost", "Launched"] as TCrmStages[]).includes(crm.stage);

const isNotProspectStage = (crm: CrmProject) => crm.stage !== "Prospect";

const hygieneIssues: THygieneIssue[] = [
{
value: "productMissing",
label: "Product missing",
description: "ARR or TCV are $0",
filterFn: (crm) => crm.arr === 0 && crm.tcv === 0,
filterFn: (crm) =>
isOpen(crm) && isNotProspectStage(crm) && crm.arr === 0 && crm.tcv === 0,
},
{
value: "closeDatePast",
label: "Close date past",
filterFn: (crm) => !isFuture(crm.closeDate),
filterFn: (crm) => isOpen(crm) && !isFuture(crm.closeDate),
},
{
value: "nonCompliantStage",
label: "Non-compliant stage",
description:
"When close date within 30 days stage must be BusVal/Committed",
filterFn: (crm) => isNonCompliantStage(crm, 0, 30),
filterFn: (crm) => isOpen(crm) && isNonCompliantStage(crm, 0, 30),
},
{
value: "almostNonCompliantStage",
label: "Almost non-compliant stage",
description:
"When close date within 45 days stage must be BusVal/Committed",
filterFn: (crm) => isNonCompliantStage(crm, 31, 45),
filterFn: (crm) => isOpen(crm) && isNonCompliantStage(crm, 31, 45),
},
{
value: "stalledOps",
label: "Stalled opps",
description: "Stage hasn't been changed in the last 90 days",
filterFn: (crm) =>
!crm.stageChangedDate ||
differenceInCalendarDays(new Date(), crm.stageChangedDate) >= 90,
isOpen(crm) &&
(!crm.stageChangedDate ||
differenceInCalendarDays(new Date(), crm.stageChangedDate) >= 90),
},
{
value: "nextStep",
label: "Next step not compliant",
description: "Next step should be updated at least once in 30 days",
filterFn: (crm) =>
!hasCompliantNextStepDateFormat(crm) || !hasCompliantNextStepDate(crm),
isOpen(crm) &&
(!hasCompliantNextStepDateFormat(crm) || !hasCompliantNextStepDate(crm)),
},
{
value: "zombies",
label: "Zombies",
description: "Opportunities older than 1 year",
filterFn: (crm) =>
isOpen(crm) &&
differenceInCalendarDays(new Date(), crm.createdDate) >= 365,
},
] as const;
Expand Down
8 changes: 2 additions & 6 deletions components/projects/ProjectAccordionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { Project } from "@/api/ContextProjects";
import { calcRevenueTwoYears, make2YearsRevenueText } from "@/helpers/projects";
import { format } from "date-fns";
import { flow, map, sum } from "lodash/fp";
import { Circle } from "lucide-react";
import { FC } from "react";
import HygieneIssueBadge from "../crm/hygiene-issue-badge";
import { hasHygieneIssues } from "../crm/pipeline-hygiene";
import TaskBadge from "../task/TaskBadge";
import DefaultAccordionItem from "../ui-elements/accordion/DefaultAccordionItem";
import ProjectDetails from "../ui-elements/project-details/project-details";
import { Badge } from "../ui/badge";

type ProjectAccordionItemProps = {
project?: Project;
Expand Down Expand Up @@ -38,10 +37,7 @@ const ProjectAccordionItem: FC<ProjectAccordionItemProps> = ({
link={`/projects/${project.id}`}
badge={
project.crmProjects.some(hasHygieneIssues) ? (
<>
<Circle className="mt-[0.2rem] w-4 min-w-4 h-4 md:hidden bg-orange-400 rounded-full text-destructive-foreground" />
<Badge className="hidden md:block bg-orange-400">Hygiene</Badge>
</>
<HygieneIssueBadge />
) : (
<TaskBadge
hasOpenTasks={openTasksByProjectId(project.id).length > 0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useProjectsContext } from "@/api/ContextProjects";
import useCrmProject from "@/api/useCrmProject";
import CrmData from "@/components/crm/CrmData";
import { makeCrmLink } from "@/components/crm/CrmLink";
import HygieneIssueBadge from "@/components/crm/hygiene-issue-badge";
import LabelData from "@/components/crm/label-data";
import NextStep from "@/components/crm/next-steps";
import { hasHygieneIssues } from "@/components/crm/pipeline-hygiene";
Expand Down Expand Up @@ -62,12 +63,7 @@ const CrmProjectDetails: FC<CrmProjectDetailsProps> = ({
</Badge>
</>
) : (
hasHygieneIssues(crmProject) && (
<>
<Circle className="mt-[0.2rem] w-4 min-w-4 h-4 md:hidden bg-orange-400 rounded-full text-destructive-foreground" />
<Badge className="hidden md:block bg-orange-400">Hygiene</Badge>
</>
)
hasHygieneIssues(crmProject) && <HygieneIssueBadge />
)
}
link={
Expand Down

0 comments on commit aaaeeef

Please sign in to comment.