Skip to content

Commit

Permalink
Merge pull request #1348 from flanksource/973-intercom-support
Browse files Browse the repository at this point in the history
973-intercom-support
  • Loading branch information
moshloop authored Sep 11, 2023
2 parents 55060a6 + d2979cc commit 8b9421f
Show file tree
Hide file tree
Showing 22 changed files with 324 additions and 120 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/organizations/create

# replace this with the actual domain where clerk based backend is hosted
NEXT_PUBLIC_CLERK_BACKEND_DOMAIN=azure.lab.flanksource.com
# NEXT_PUBLIC_INTERCOM_APP_ID=
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@tanstack/react-virtual": "^3.0.0-beta.30",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/intercom-web": "^2.8.21",
"@types/jest": "^29.2.5",
"@types/node": "^17.0.36",
"@types/react": "^18.0.9",
Expand Down Expand Up @@ -74,6 +75,7 @@
"react-toastify": "^9.0.8",
"react-tooltip": "^4.2.21",
"react-top-loading-bar": "^2.3.1",
"react-use-intercom": "^5.1.4",
"recharts": "2.1.12",
"tailwindcss": "^3.0.24",
"timeago.js": "^4.0.2",
Expand Down
2 changes: 1 addition & 1 deletion pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Document, { Head, Html, Main, NextScript } from "next/document";
import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";

export default class MyDocument extends Document {
render() {
Expand Down
33 changes: 18 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { HealthPage } from "./pages/health";
import { features } from "./services/permissions/features";
import { stringSortHelper } from "./utils/common";
import { PlaybookSettingsPage } from "./pages/Settings/PlaybookSettingsPage";
import SetupIntercom from "./components/Intercom/SetupIntercom";

export type NavigationItems = {
name: string;
Expand Down Expand Up @@ -488,21 +489,23 @@ export function App() {
<BrowserRouter>
<Provider>
<AuthProviderWrapper>
<UserAccessStateContextProvider>
<FeatureFlagsContextProvider>
<TopologyPageContextProvider>
<HealthPageContextProvider>
<ConfigPageContextProvider>
<IncidentPageContextProvider>
<ReactTooltip />
<IncidentManagerRoutes sidebar={<SidebarWrapper />} />
<ReactQueryDevtools initialIsOpen={false} />
</IncidentPageContextProvider>
</ConfigPageContextProvider>
</HealthPageContextProvider>
</TopologyPageContextProvider>
</FeatureFlagsContextProvider>
</UserAccessStateContextProvider>
<SetupIntercom>
<UserAccessStateContextProvider>
<FeatureFlagsContextProvider>
<TopologyPageContextProvider>
<HealthPageContextProvider>
<ConfigPageContextProvider>
<IncidentPageContextProvider>
<ReactTooltip />
<IncidentManagerRoutes sidebar={<SidebarWrapper />} />
<ReactQueryDevtools initialIsOpen={false} />
</IncidentPageContextProvider>
</ConfigPageContextProvider>
</HealthPageContextProvider>
</TopologyPageContextProvider>
</FeatureFlagsContextProvider>
</UserAccessStateContextProvider>
</SetupIntercom>
</AuthProviderWrapper>
</Provider>
</BrowserRouter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";
import {
SchemaApi,
SchemaResourceType
} from "../../../components/SchemaResourcePage/resourceTypes";
import { toastSuccess, toastError } from "../../../components/Toast/toast";
import { toastError, toastSuccess } from "../../../components/Toast/toast";
import { useUser } from "../../../context";
import {
SchemaResourceI,
createResource,
deleteResource,
updateResource
} from "../../schemaResources";
import { useNavigate } from "react-router-dom";
import { useUser } from "../../../context";

export const useSettingsDeleteResource = (
resourceInfo: Pick<SchemaResourceType, "name" | "table" | "api">,
Expand Down
2 changes: 2 additions & 0 deletions src/components/AttachEvidenceDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { severityItems, typeItems } from "../Incidents/data";
import { ReactSelectDropdown } from "../ReactSelectDropdown";
import { useQueryClient } from "@tanstack/react-query";
import { createIncidentQueryKey } from "../../api/query-hooks";
import { Events, sendAnalyticEvent } from "../../services/analytics";

interface Props {
title?: string;
Expand Down Expand Up @@ -311,6 +312,7 @@ export function AttachEvidenceDialog({

try {
await createEvidence(evidence);
sendAnalyticEvent(Events.AttachEvidenceToIncident);
toastSuccess(
<div>
Linked to{" "}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useUpdateEvidenceMutation } from "../../../api/query-hooks/mutations/ev
import { Evidence, EvidenceType } from "../../../api/services/evidence";
import { ScriptStep } from "./steps/ScriptStep";
import EvidenceSelectorStep from "./steps/EvidenceSelectorStep";
import { Events, sendAnalyticEvent } from "../../../services/analytics";

export type DefinitionOfDoneType = `${EvidenceType}`;

Expand Down Expand Up @@ -115,6 +116,7 @@ export default function AddAutoDefinitionOfDoneStepper({
const { isLoading, mutate: updateEvidence } = useUpdateEvidenceMutation(
{
onSuccess: (evidence) => {
sendAnalyticEvent(Events.AddedDoDToIncident);
onAddDefinitionOfDone(evidence);
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import SelectPeopleResponderDropdown from "./SelectPeopleResponderDropdown";
import SelectTeamResponderDropdown from "./SelectTeamResponderDropdown";
import TeamResponderTypeForm from "./TeamResponderTypeForm";
import { Events, sendAnalyticEvent } from "../../../services/analytics";

export type SelectedResponderType = {
value: string;
Expand Down Expand Up @@ -193,6 +194,7 @@ export default function AddResponderModal({
responder: Omit<Responder, "id" | "updated_at" | "created_at">
) => saveResponder(responder),
onSuccess: (_) => {
sendAnalyticEvent(Events.AddedResponderToIncident);
toastSuccess("Responder added successfully");
onSuccess();
closeModal();
Expand Down
51 changes: 32 additions & 19 deletions src/components/Incidents/IncidentCreate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@ import { useNavigate, useSearchParams } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import * as yup from "yup";
import {
createEvidence,
Evidence,
EvidenceType
EvidenceType,
createEvidence
} from "../../../api/services/evidence";
import {
createHypothesisOld,
HypothesisStatus
HypothesisStatus,
createHypothesisOld
} from "../../../api/services/hypothesis";
import { createIncident, Incident } from "../../../api/services/incident";
import {
Incident,
IncidentStatus,
NewIncident,
createIncident
} from "../../../api/services/incident";
import { useUser } from "../../../context";
import { Events, sendAnalyticEvent } from "../../../services/analytics";
import { Button } from "../../Button";
import { ReactSelectDropdown } from "../../ReactSelectDropdown";
import { TextInput } from "../../TextInput";
import { toastError } from "../../Toast/toast";
import { severityItems, incidentStatusItems, typeItems } from "../data";
import { Button } from "../../Button";
import { incidentStatusItems, severityItems, typeItems } from "../data";

const validationSchema = yup
.object({
Expand Down Expand Up @@ -57,13 +63,15 @@ export function IncidentCreate({
formState: { errors },
handleSubmit,
watch
} = useForm({
} = useForm<
Omit<NewIncident, "created_by" | "commander_id" | "communicator_id">
>({
defaultValues: {
title: "",
description: "",
// tracking: "",
severity: "Low",
status: "open",
status: IncidentStatus.Open,
type: "availability"
},
resolver: yupResolver(validationSchema)
Expand All @@ -82,13 +90,14 @@ export function IncidentCreate({
updated_at: "now()"
};

const onSubmit = async (data: Record<string, any>) => {
const payload: Record<string, any> = { ...data, ...additionalFields };
const onSubmit = async (
data: Omit<NewIncident, "created_by" | "commander_id" | "communicator_id">
) => {
const payload = { ...data, ...additionalFields };
payload.id = uuidv4();
// TODO(ciju): Handle failure cases
try {
// @ts-expect-error
const { data: incident, error } = await createIncident(user!, payload);
const { data: incident } = await createIncident(user!, payload);

const hypothesis = await createHypothesisOld(
user!,
Expand All @@ -106,12 +115,13 @@ export function IncidentCreate({
return;
}

let _evidence: Evidence = {
// @ts-expect-error
user,
id: uuidv4(),
let _evidence: Omit<
Evidence,
"created_by" | "created_at" | "hypothesis_id" | "id"
> = {
user: user!,
hypothesisId: hypothesis.data[0].id
};
} as any;

if (evidence) {
_evidence.evidence = {
Expand All @@ -130,6 +140,9 @@ export function IncidentCreate({

await createEvidence(_evidence);

// Send Intercom event, when incident is created
sendAnalyticEvent(Events.CreatedIncident);

if (callback != null) {
callback(incident);
} else {
Expand Down Expand Up @@ -237,7 +250,7 @@ export function IncidentCreate({
/>
<p className="text-red-600 text-sm">{errors.commander_id?.message}</p>
</div> */}
{/* <div className="mb-4">
{/* <div className="mb-4">
<Controller
control={control}
name="tracking"
Expand Down
73 changes: 73 additions & 0 deletions src/components/Intercom/BootIntercom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useAuth, useUser } from "@clerk/nextjs";
import { useEffect } from "react";
import { useIntercom } from "react-use-intercom";
import { useUser as useContextUser } from "../../context";
import useDetermineAuthSystem from "../Authentication/useDetermineAuthSystem";

type Props = {
children: React.ReactNode;
};

function BootIntercomForClerk({ children }: Props) {
const { boot, shutdown } = useIntercom();
const { user } = useContextUser();
const { user: clerkUser } = useUser();
const { isSignedIn, isLoaded } = useAuth();

useEffect(() => {
boot({
name: user?.name,
email: user?.email,
userId: user?.id,
avatar: {
type: "avatar",
imageUrl: user?.avatar
},
companies: clerkUser?.organizationMemberships.map((membership) => ({
companyId: membership.id,
name: membership.organization.name
}))
});
}, [boot, clerkUser, user]);

// on sign out, shutdown intercom
useEffect(() => {
if (!isSignedIn && isLoaded) {
shutdown();
}
}, [isSignedIn, isLoaded, shutdown]);

// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}

function BootIntercomForKratos({ children }: Props) {
const { boot } = useIntercom();
const { user } = useContextUser();

useEffect(() => {
boot({
name: user?.name,
email: user?.email,
userId: user?.id,
avatar: {
type: "avatar",
imageUrl: user?.avatar
}
});
}, [boot, user]);

// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}

export default function BootIntercom({ children }: Props) {
const authSystem = useDetermineAuthSystem();

if (authSystem === "clerk") {
return <BootIntercomForClerk>{children}</BootIntercomForClerk>;
}

// eslint-disable-next-line react/jsx-no-useless-fragment
return <BootIntercomForKratos>{children}</BootIntercomForKratos>;
}
Loading

0 comments on commit 8b9421f

Please sign in to comment.