fix/auto-connect-calendar-3582 (#3891)

* Added alert when there isn't default calendar connected

* Add default calendar externalId to select placeholder

* Fix typos

* Fixes prisma import

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
alannnc 2022-08-22 13:34:28 -06:00 committed by GitHub
parent 662b437a18
commit b328527434
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 19 deletions

View File

@ -3,6 +3,7 @@ import React, { useEffect, useState } from "react";
import Select from "react-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { DestinationCalendar } from "@calcom/prisma/client";
import { trpc } from "@calcom/trpc/react";
interface Props {
@ -11,6 +12,7 @@ interface Props {
hidePlaceholder?: boolean;
/** The external Id of the connected calendar */
value: string | undefined;
destinationCalendar?: DestinationCalendar | null;
}
const DestinationCalendarSelector = ({
@ -18,6 +20,7 @@ const DestinationCalendarSelector = ({
isLoading,
value,
hidePlaceholder,
destinationCalendar,
}: Props): JSX.Element | null => {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.connectedCalendars"]);
@ -67,11 +70,20 @@ const DestinationCalendarSelector = ({
value: `${cal.integration}:${cal.externalId}`,
})),
})) ?? [];
return (
<div className="relative" title={`${t("select_destination_calendar")}: ${selectedOption?.label || ""}`}>
<Select
name="primarySelectedCalendar"
placeholder={!hidePlaceholder ? `${t("select_destination_calendar")}:` : undefined}
placeholder={
!hidePlaceholder ? (
`${t("select_destination_calendar")}`
) : (
<span>
{t("default_calendar_selected")} ({destinationCalendar?.externalId})
</span>
)
}
options={options}
styles={{
placeholder: (styles) => ({ ...styles, ...content(hidePlaceholder) }),

View File

@ -9,11 +9,11 @@ import { useForm } from "react-hook-form";
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import prisma from "@calcom/prisma";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Icon } from "@calcom/ui/Icon";
import { EmailField, Form, PasswordField } from "@calcom/ui/form/fields";
import prisma from "@calcom/web/lib/prisma";
import { ErrorCode, getSession } from "@lib/auth";
import { WEBAPP_URL, WEBSITE_URL } from "@lib/config/constants";

View File

@ -1099,6 +1099,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
defaultValue={eventType.destinationCalendar || undefined}
render={({ field: { onChange, value } }) => (
<DestinationCalendarSelector
destinationCalendar={connectedCalendarsQuery.data?.destinationCalendar}
value={value ? value.externalId : undefined}
onChange={onChange}
hidePlaceholder

View File

@ -1,4 +1,5 @@
import { UserPlan } from "@prisma/client";
import { GetServerSidePropsContext, InferGetServerSidePropsType } from "next";
import { Trans } from "next-i18next";
import Head from "next/head";
import Link from "next/link";
@ -8,6 +9,7 @@ import React, { Fragment, useEffect, useState } from "react";
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import prisma from "@calcom/prisma";
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
import { Button } from "@calcom/ui";
import { Alert } from "@calcom/ui/Alert";
@ -26,6 +28,7 @@ import Shell from "@calcom/ui/Shell";
import { Tooltip } from "@calcom/ui/Tooltip";
import { withQuery } from "@lib/QueryCell";
import { getSession } from "@lib/auth";
import classNames from "@lib/classNames";
import { HttpError } from "@lib/core/http/error";
@ -69,8 +72,6 @@ const Item = ({
}) => {
const { t } = useLocale();
const isCalendarConnectedMissing = connectedCalendars?.length && !type.team && !type.destinationCalendar;
return (
<Link href={"/event-types/" + type.id}>
<a
@ -93,11 +94,7 @@ const Item = ({
{t("hidden") as string}
</span>
)}
{/* TODO: find a better way to do this !!isCalendarConnectedMissing && (
<span className="rtl:mr-2inline items-center rounded-sm bg-red-100 px-1.5 py-0.5 text-xs font-medium text-red-800 ltr:ml-2">
{t("missing_connected_calendar") as string}
</span>
)*/}
{readOnly && (
<span className="rtl:mr-2inline items-center rounded-sm bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 ltr:ml-2">
{t("readonly") as string}
@ -574,8 +571,10 @@ const CTA = () => {
const WithQuery = withQuery(["viewer.eventTypes"]);
const EventTypesPage = () => {
const EventTypesPage = (props: InferGetServerSidePropsType<typeof getServerSideProps>) => {
const { t } = useLocale();
const { defaultCalendarConnected } = props;
return (
<div>
<Head>
@ -607,6 +606,23 @@ const EventTypesPage = () => {
className="mb-4"
/>
)}
{!defaultCalendarConnected && (
<Alert
severity="warning"
className="mb-4"
title={<>{t("missing_connected_calendar") as string}</>}
message={
<Trans i18nKey="connect_your_calendar_and_link">
You can connect your calendar from
<a href="/apps/categories/calendar" className="underline">
here
</a>
.
</Trans>
}
/>
)}
{data.eventTypeGroups.map((group, index) => (
<Fragment key={group.profile.slug}>
{/* hide list heading when there is only one (current user) */}
@ -616,6 +632,7 @@ const EventTypesPage = () => {
membershipCount={group.metadata.membershipCount}
/>
)}
<EventTypeList
types={group.eventTypes}
group={group}
@ -635,4 +652,26 @@ const EventTypesPage = () => {
);
};
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession(context);
let defaultCalendarConnected = false;
if (session && session.user) {
const defaultCalendar = await prisma.destinationCalendar.findFirst({
where: {
userId: session.user.id,
credentialId: {
not: null,
},
},
});
defaultCalendarConnected = !!defaultCalendar;
}
return {
props: {
defaultCalendarConnected,
},
};
}
export default EventTypesPage;

View File

@ -1028,13 +1028,15 @@
"current_username": "Current username",
"example_1": "Example 1",
"example_2": "Example 2",
"additonal_input_label": "Additonal input label",
"additional_input_label": "Additional input label",
"company_size": "Company size",
"what_help_needed": "What do you need help with?",
"variable_format": "Variable format",
"custom_input_as_variable_info": "Ignore all special characters of the additonal input label (use only letters and numbers), use uppercase for all letters and replace whitespaces with underscores.",
"custom_input_as_variable_info": "Ignore all special characters of the additional input label (use only letters and numbers), use uppercase for all letters and replace whitespaces with underscores.",
"using_additional_inputs_as_variables": "How to use additional inputs as variables?",
"missing_connected_calendar": "No calendar connected",
"download_desktop_app": "Download desktop app",
"set_ping_link": "Set Ping link"
"set_ping_link": "Set Ping link",
"missing_connected_calendar": "No default calendar connected",
"connect_your_calendar_and_link": "You can connect your calendar from <1>here</1>.",
"default_calendar_selected": "Default calendar"
}

View File

@ -1,4 +1,4 @@
import prisma from "@calcom/web/lib/prisma";
import prisma from "@calcom/prisma";
export * from "@calcom/app-store/_apps-playwright/lib/testUtils";
export async function cleanUpForms() {

View File

@ -0,0 +1,17 @@
-- DropForeignKey
ALTER TABLE "DestinationCalendar" DROP CONSTRAINT "DestinationCalendar_credentialId_fkey";
-- DropForeignKey
ALTER TABLE "DestinationCalendar" DROP CONSTRAINT "DestinationCalendar_eventTypeId_fkey";
-- DropForeignKey
ALTER TABLE "DestinationCalendar" DROP CONSTRAINT "DestinationCalendar_userId_fkey";
-- AddForeignKey
ALTER TABLE "DestinationCalendar" ADD CONSTRAINT "DestinationCalendar_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "DestinationCalendar" ADD CONSTRAINT "DestinationCalendar_eventTypeId_fkey" FOREIGN KEY ("eventTypeId") REFERENCES "EventType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "DestinationCalendar" ADD CONSTRAINT "DestinationCalendar_credentialId_fkey" FOREIGN KEY ("credentialId") REFERENCES "Credential"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -85,6 +85,7 @@ model EventType {
model Credential {
id Int @id @default(autoincrement())
// @@type is deprecated
type String
key Json
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
@ -111,13 +112,13 @@ model DestinationCalendar {
id Int @id @default(autoincrement())
integration String
externalId String
user User? @relation(fields: [userId], references: [id])
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int? @unique
booking Booking[]
eventType EventType? @relation(fields: [eventTypeId], references: [id])
eventType EventType? @relation(fields: [eventTypeId], references: [id], onDelete: Cascade)
eventTypeId Int? @unique
credentialId Int?
credential Credential? @relation(fields: [credentialId], references: [id])
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
}
enum UserPermissionRole {

View File

@ -1,7 +1,7 @@
import { GetServerSidePropsContext, GetServerSidePropsResult } from "next";
import { CalendsoSessionUser } from "next-auth";
import prisma from "@calcom/web/lib/prisma";
import prisma from "@calcom/prisma";
export type AppUser = CalendsoSessionUser | undefined;
export type AppPrisma = typeof prisma;