From 492881b3facb6c6d1fdf1e5b63b8a8e7e28d2ec4 Mon Sep 17 00:00:00 2001 From: CarinaWolli Date: Tue, 19 Jul 2022 20:10:41 -0400 Subject: [PATCH 1/4] implement feedback --- .../workflows/WorkflowDetailsPage.tsx | 41 ++++++++++--------- .../workflows/WorkflowStepContainer.tsx | 5 +-- .../reminders/emailReminderManager.ts | 5 ++- .../workflows/reminders/smsReminderManager.ts | 2 +- apps/web/ee/pages/workflows/[workflow].tsx | 13 ++---- .../templates/workflow-reminder-email.ts | 12 ------ 6 files changed, 31 insertions(+), 47 deletions(-) diff --git a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx index 4641815922bdca..745bbe5cd4b2f2 100644 --- a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx +++ b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx @@ -1,6 +1,6 @@ import { WorkflowActions, WorkflowTemplates } from "@prisma/client"; import { useRouter } from "next/router"; -import { useState, useEffect, Dispatch, SetStateAction } from "react"; +import { useState, useEffect, Dispatch, SetStateAction, useMemo } from "react"; import { Controller, UseFormReturn } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ -10,14 +10,14 @@ import { Button } from "@calcom/ui"; import { Form } from "@calcom/ui/form/fields"; import { AddActionDialog } from "@ee/components/workflows/AddActionDialog"; import WorkflowStepContainer from "@ee/components/workflows/WorkflowStepContainer"; -import { Option, FormValues } from "@ee/pages/workflows/[workflow]"; +import { FormValues } from "@ee/pages/workflows/[workflow]"; import { trpc } from "@lib/trpc"; -import MultiSelectCheckboxes from "@components/ui/form/MultiSelectCheckboxes"; +import MultiSelectCheckboxes, { Option } from "@components/ui/form/MultiSelectCheckboxes"; interface Props { - form: UseFormReturn; + form: UseFormReturn; workflowId: number; selectedEventTypes: Option[]; setSelectedEventTypes: Dispatch>; @@ -29,30 +29,31 @@ export default function WorkflowDetailsPage(props: Props) { const router = useRouter(); const utils = trpc.useContext(); - const [evenTypeOptions, setEventTypeOptions] = useState([]); const [isAddActionDialogOpen, setIsAddActionDialogOpen] = useState(false); const [reload, setReload] = useState(false); const [editCounter, setEditCounter] = useState(0); const { data, isLoading } = trpc.useQuery(["viewer.eventTypes"]); - useEffect(() => { - if (data) { - let options: Option[] = []; - data.eventTypeGroups.forEach((group) => { - const eventTypeOptions = group.eventTypes.map((eventType) => { - return { value: String(eventType.id), label: eventType.title }; - }); - options = [...options, ...eventTypeOptions]; - }); - setEventTypeOptions(options); - } - }, [isLoading]); + const eventTypeOptions = useMemo( + () => + data?.eventTypeGroups.reduce( + (options, group) => [ + ...options, + ...group.eventTypes.map((eventType) => ({ + value: String(eventType.id), + label: eventType.title, + })), + ], + [] as Option[] + ) || [], + [data] + ); const updateMutation = trpc.useMutation("viewer.workflows.update", { onSuccess: async ({ workflow }) => { if (workflow) { - await utils.setQueryData(["viewer.workflows.get", { id: +workflow.id }], workflow); + utils.setQueryData(["viewer.workflows.get", { id: +workflow.id }], workflow); showToast( t("workflow_updated_successfully", { @@ -74,7 +75,7 @@ export default function WorkflowDetailsPage(props: Props) { const addAction = (action: WorkflowActions, sendTo?: string) => { const steps = form.getValues("steps"); const id = - steps && steps.length > 0 + steps?.length > 0 ? steps.sort((a, b) => { return a.id - b.id; })[0].id - 1 @@ -130,7 +131,7 @@ export default function WorkflowDetailsPage(props: Props) { render={() => { return ( ; diff --git a/apps/web/ee/lib/workflows/reminders/emailReminderManager.ts b/apps/web/ee/lib/workflows/reminders/emailReminderManager.ts index 1d15d6254d7046..76bbb0a80954f2 100644 --- a/apps/web/ee/lib/workflows/reminders/emailReminderManager.ts +++ b/apps/web/ee/lib/workflows/reminders/emailReminderManager.ts @@ -46,7 +46,10 @@ export const scheduleEmailReminder = async ( const scheduledDate = timeBefore.time && timeUnit ? dayjs(startTime).subtract(timeBefore.time, timeUnit) : null; - if (!process.env.SENDGRID_API_KEY || !process.env.SENDGRID_EMAIL) return; + if (!process.env.SENDGRID_API_KEY || !process.env.SENDGRID_EMAIL) { + console.error("Sendgrid credentials are missing from the .env file"); + return; + } const batchIdResponse = await client.request({ url: "/v3/mail/batch", diff --git a/apps/web/ee/lib/workflows/reminders/smsReminderManager.ts b/apps/web/ee/lib/workflows/reminders/smsReminderManager.ts index 78473f2ea401b3..62745da6857333 100644 --- a/apps/web/ee/lib/workflows/reminders/smsReminderManager.ts +++ b/apps/web/ee/lib/workflows/reminders/smsReminderManager.ts @@ -4,7 +4,7 @@ import { WorkflowTemplates, WorkflowActions, WorkflowMethods, -} from "@prisma/client/"; +} from "@prisma/client"; import dayjs from "@calcom/dayjs"; import prisma from "@calcom/prisma"; diff --git a/apps/web/ee/pages/workflows/[workflow].tsx b/apps/web/ee/pages/workflows/[workflow].tsx index 3365b37de26d70..e253d6bbd9ab04 100644 --- a/apps/web/ee/pages/workflows/[workflow].tsx +++ b/apps/web/ee/pages/workflows/[workflow].tsx @@ -24,11 +24,7 @@ import useMeQuery from "@lib/hooks/useMeQuery"; import { trpc } from "@lib/trpc"; import Shell from "@components/Shell"; - -export type Option = { - value: string; - label: string; -}; +import { Option } from "@components/ui/form/MultiSelectCheckboxes"; export type FormValues = { name: string; @@ -113,15 +109,12 @@ function WorkflowPage() { } }, [dataUpdatedAt]); - if (isLoading) { - return ; - } - return ( setEditIcon(false)}> {editIcon ? ( <> diff --git a/packages/emails/templates/workflow-reminder-email.ts b/packages/emails/templates/workflow-reminder-email.ts index b1565001ce0917..e9faa079a0bba4 100644 --- a/packages/emails/templates/workflow-reminder-email.ts +++ b/packages/emails/templates/workflow-reminder-email.ts @@ -1,17 +1,5 @@ -import dayjs from "@calcom/dayjs"; -import localizedFormat from "dayjs/plugin/localizedFormat"; -import timezone from "dayjs/plugin/timezone"; -import toArray from "dayjs/plugin/toArray"; -import utc from "dayjs/plugin/utc"; - import BaseEmail from "./_base-email"; import { BookingInfo } from "@calcom/web/ee/lib/workflows/reminders/smsReminderManager"; - -dayjs.extend(utc); -dayjs.extend(timezone); -dayjs.extend(localizedFormat); -dayjs.extend(toArray); - export default class WorkflowReminderEmail extends BaseEmail { sendTo: string; body: string; From 8981918180e7ab22f738c9f74e65fe5494fc2e4a Mon Sep 17 00:00:00 2001 From: CarinaWolli Date: Tue, 19 Jul 2022 20:22:05 -0400 Subject: [PATCH 2/4] put formSchema outside of react component --- apps/web/ee/pages/workflows/[workflow].tsx | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/web/ee/pages/workflows/[workflow].tsx b/apps/web/ee/pages/workflows/[workflow].tsx index e253d6bbd9ab04..7128dd08b92ee0 100644 --- a/apps/web/ee/pages/workflows/[workflow].tsx +++ b/apps/web/ee/pages/workflows/[workflow].tsx @@ -35,6 +35,30 @@ export type FormValues = { timeUnit?: TimeUnit; }; +const formSchema = z.object({ + name: z.string(), + activeOn: z.object({ value: z.string(), label: z.string() }).array(), + trigger: z.enum(WORKFLOW_TRIGGER_EVENTS), + time: z.number().gte(0).optional(), + timeUnit: z.enum(TIME_UNIT).optional(), + steps: z + .object({ + id: z.number(), + stepNumber: z.number(), + action: z.enum(WORKFLOW_ACTIONS), + workflowId: z.number(), + reminderBody: z.string().optional().nullable(), + emailSubject: z.string().optional().nullable(), + template: z.enum(WORKFLOW_TEMPLATES), + sendTo: z + .string() + .refine((val) => isValidPhoneNumber(val)) + .optional() + .nullable(), + }) + .array(), +}); + function WorkflowPage() { const { t } = useLocale(); const session = useSession(); @@ -46,30 +70,6 @@ function WorkflowPage() { const [selectedEventTypes, setSelectedEventTypes] = useState([]); const [isAllDataLoaded, setIsAllDataLoaded] = useState(false); - const formSchema = z.object({ - name: z.string(), - activeOn: z.object({ value: z.string(), label: z.string() }).array(), - trigger: z.enum(WORKFLOW_TRIGGER_EVENTS), - time: z.number().gte(0).optional(), - timeUnit: z.enum(TIME_UNIT).optional(), - steps: z - .object({ - id: z.number(), - stepNumber: z.number(), - action: z.enum(WORKFLOW_ACTIONS), - workflowId: z.number(), - reminderBody: z.string().optional().nullable(), - emailSubject: z.string().optional().nullable(), - template: z.enum(WORKFLOW_TEMPLATES), - sendTo: z - .string() - .refine((val) => isValidPhoneNumber(val)) - .optional() - .nullable(), - }) - .array(), - }); - const form = useForm({ resolver: zodResolver(formSchema), }); From 5117c0c66c3f51e1baccb3b1e8f31c73c98945ba Mon Sep 17 00:00:00 2001 From: CarinaWolli Date: Tue, 19 Jul 2022 20:22:59 -0400 Subject: [PATCH 3/4] don't show new workflow button for free Users --- apps/web/ee/pages/workflows/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/ee/pages/workflows/index.tsx b/apps/web/ee/pages/workflows/index.tsx index d2fc642482b921..a324eb6b3d056d 100644 --- a/apps/web/ee/pages/workflows/index.tsx +++ b/apps/web/ee/pages/workflows/index.tsx @@ -26,7 +26,7 @@ function WorkflowsPage() { : <>}> + CTA={session.data?.hasValidLicense && !isFreeUser ? : <>}> {isLoading ? ( From 17b58124113dc95973678df5501eefc1ddcb1c37 Mon Sep 17 00:00:00 2001 From: CarinaWolli Date: Tue, 19 Jul 2022 20:52:01 -0400 Subject: [PATCH 4/4] code clean up --- apps/web/ee/components/workflows/WorkflowDetailsPage.tsx | 2 +- apps/web/ee/components/workflows/WorkflowStepContainer.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx index 745bbe5cd4b2f2..51659d67623546 100644 --- a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx +++ b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx @@ -1,6 +1,6 @@ import { WorkflowActions, WorkflowTemplates } from "@prisma/client"; import { useRouter } from "next/router"; -import { useState, useEffect, Dispatch, SetStateAction, useMemo } from "react"; +import { useState, Dispatch, SetStateAction, useMemo } from "react"; import { Controller, UseFormReturn } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; diff --git a/apps/web/ee/components/workflows/WorkflowStepContainer.tsx b/apps/web/ee/components/workflows/WorkflowStepContainer.tsx index 7ee65c2a7549e3..9c1dd6f2d7e904 100644 --- a/apps/web/ee/components/workflows/WorkflowStepContainer.tsx +++ b/apps/web/ee/components/workflows/WorkflowStepContainer.tsx @@ -27,7 +27,7 @@ import { FormValues } from "@ee/pages/workflows/[workflow]"; type WorkflowStepProps = { step?: WorkflowStep; - form: UseFormReturn; + form: UseFormReturn; reload?: boolean; setReload?: Dispatch>; editCounter: number;