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:
parent
662b437a18
commit
b328527434
|
@ -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) }),
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user