diff --git a/apps/web/components/apps/App.tsx b/apps/web/components/apps/App.tsx index 2a9bba10bf..2d50a62002 100644 --- a/apps/web/components/apps/App.tsx +++ b/apps/web/components/apps/App.tsx @@ -4,21 +4,14 @@ import React, { useState } from "react"; import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation"; import { InstallAppButton } from "@calcom/app-store/components"; +import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration"; import LicenseRequired from "@calcom/features/ee/common/components/v2/LicenseRequired"; import classNames from "@calcom/lib/classNames"; import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { App as AppType } from "@calcom/types/App"; -import { - Button, - DisconnectIntegration, - Icon, - Shell, - showToast, - SkeletonButton, - SkeletonText, -} from "@calcom/ui"; +import { Button, Icon, Shell, showToast, SkeletonButton, SkeletonText } from "@calcom/ui"; import HeadSeo from "@components/seo/head-seo"; diff --git a/apps/web/components/apps/CalendarListContainer.tsx b/apps/web/components/apps/CalendarListContainer.tsx index 35adbf3c10..39d04eb38d 100644 --- a/apps/web/components/apps/CalendarListContainer.tsx +++ b/apps/web/components/apps/CalendarListContainer.tsx @@ -3,13 +3,13 @@ import Link from "next/link"; import { Fragment } from "react"; import { InstallAppButton } from "@calcom/app-store/components"; +import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration"; import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Alert, Button, - DisconnectIntegration, EmptyScreen, Icon, List, diff --git a/apps/web/components/eventtype/CreateEventType.tsx b/apps/web/components/eventtype/CreateEventType.tsx deleted file mode 100644 index c732671227..0000000000 --- a/apps/web/components/eventtype/CreateEventType.tsx +++ /dev/null @@ -1,350 +0,0 @@ -import { zodResolver } from "@hookform/resolvers/zod"; -import { SchedulingType } from "@prisma/client"; -import { useSession } from "next-auth/react"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; -import { useForm } from "react-hook-form"; -import type { z } from "zod"; - -import classNames from "@calcom/lib/classNames"; -import { WEBAPP_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { createEventTypeInput } from "@calcom/prisma/zod/custom/eventtype"; -import { trpc } from "@calcom/trpc/react"; -import { - Alert, - Button, - Dialog, - DialogClose, - DialogContent, - Dropdown, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, - Form, - Icon, - InputLeading, - showToast, - TextAreaField, - TextField, -} from "@calcom/ui"; - -import { HttpError } from "@lib/core/http/error"; -import { slugify } from "@lib/slugify"; - -import Avatar from "@components/ui/Avatar"; -import * as RadioArea from "@components/ui/form/radio-area"; - -// this describes the uniform data needed to create a new event type on Profile or Team -export interface EventTypeParent { - teamId: number | null | undefined; // if undefined, then it's a profile - name?: string | null; - slug?: string | null; - image?: string | null; -} - -interface CreateEventTypeBtnProps { - // set true for use on the team settings page - canAddEvents: boolean; - // set true when in use on the team settings page - isIndividualTeam?: boolean; - // EventTypeParent can be a profile (as first option) or a team for the rest. - options: EventTypeParent[]; -} - -export default function CreateEventTypeButton(props: CreateEventTypeBtnProps) { - const { t, isLocaleReady } = useLocale(); - const router = useRouter(); - // URL encoded params - const teamId: number | undefined = - typeof router.query.teamId === "string" && router.query.teamId - ? parseInt(router.query.teamId) - : undefined; - const pageSlug = router.query.eventPage || props.options[0].slug; - const hasTeams = !!props.options.find((option) => option.teamId); - const type: string = typeof router.query.type == "string" && router.query.type ? router.query.type : ""; - - const form = useForm>({ - resolver: zodResolver(createEventTypeInput), - }); - const { setValue, watch, register } = form; - - useEffect(() => { - if (!router.isReady) return; - - const title: string = - typeof router.query.title === "string" && router.query.title ? router.query.title : ""; - const length: number = - typeof router.query.length === "string" && router.query.length ? parseInt(router.query.length) : 15; - const description: string = - typeof router.query.description === "string" && router.query.description - ? router.query.description - : ""; - const slug: string = typeof router.query.slug === "string" && router.query.slug ? router.query.slug : ""; - - setValue("title", title); - setValue("length", length); - setValue("description", description); - setValue("slug", slug); - // If query params change, update the form - }, [router.isReady, router.query, setValue]); - - useEffect(() => { - const subscription = watch((value, { name, type }) => { - if (name === "title" && type === "change") { - if (value.title) setValue("slug", slugify(value.title)); - else setValue("slug", ""); - } - }); - return () => subscription.unsubscribe(); - }, [watch, setValue]); - - const createMutation = trpc.viewer.eventTypes.create.useMutation({ - onSuccess: async ({ eventType }) => { - await router.replace("/event-types/" + eventType.id); - showToast(t("event_type_created_successfully", { eventTypeTitle: eventType.title }), "success"); - }, - onError: (err) => { - if (err instanceof HttpError) { - const message = `${err.statusCode}: ${err.message}`; - showToast(message, "error"); - } - - if (err.data?.code === "BAD_REQUEST") { - const message = `${err.data.code}: URL already exists.`; - showToast(message, "error"); - } - - if (err.data?.code === "UNAUTHORIZED") { - const message = `${err.data.code}: You are not able to create this event`; - showToast(message, "error"); - } - }, - }); - - // inject selection data into url for correct router history - const openModal = (option: EventTypeParent) => { - const query = { - ...router.query, - dialog: "new-eventtype", - eventPage: option.slug, - teamId: option.teamId, - }; - if (!option.teamId) { - delete query.teamId; - } - router.push( - { - pathname: router.pathname, - query, - }, - undefined, - { shallow: true } - ); - }; - if (!isLocaleReady) { - return null; - } - return ( - - - - -
- -
-

{t("new_event_type_to_book_description")}

-
-
-
{ - createMutation.mutate(values); - }}> -
- {teamId && ( - - )} - - - {process.env.NEXT_PUBLIC_WEBSITE_URL !== undefined && - process.env.NEXT_PUBLIC_WEBSITE_URL?.length >= 21 ? ( - /{pageSlug}/} - {...register("slug")} - /> - ) : ( - - {process.env.NEXT_PUBLIC_WEBSITE_URL}/{pageSlug}/ - - } - {...register("slug")} - /> - )} - - - -
- -
- {t("minutes")} -
-
- - {teamId && ( -
- - {form.formState.errors.schedulingType && ( - - )} - form.setValue("schedulingType", val as SchedulingType)} - className="relative mt-1 flex space-x-6 rounded-sm rtl:space-x-reverse"> - - {t("collective")} -

{t("collective_description")}

-
- - {t("round_robin")} -

{t("round_robin_description")}

-
-
-
- )} -
-
- - -
-
-
-
- ); -} - -type CreateEventTypeTrigger = { - isIndividualTeam?: boolean; - // EventTypeParent can be a profile (as first option) or a team for the rest. - options: EventTypeParent[]; - hasTeams: boolean; - // set true for use on the team settings page - canAddEvents: boolean; - openModal: (option: EventTypeParent) => void; -}; - -export function CreateEventTypeTrigger(props: CreateEventTypeTrigger) { - const { t } = useLocale(); - - return ( - <> - {!props.hasTeams || props.isIndividualTeam ? ( - - ) : ( - - - - - - {t("new_event_subtitle")} - - {props.options.map((option) => ( - props.openModal(option)} - /> - ))} - - - )} - - ); -} - -function CreateEventTeamsItem(props: { - openModal: (option: EventTypeParent) => void; - option: EventTypeParent; -}) { - const session = useSession(); - const membershipQuery = trpc.viewer.teams.getMembershipbyUser.useQuery({ - memberId: session.data?.user.id as number, - teamId: props.option.teamId as number, - }); - - const isDisabled = membershipQuery.data?.role === "MEMBER"; - - return ( - props.openModal(props.option)}> - - {props.option.name ? props.option.name : props.option.slug} - - ); -} diff --git a/apps/web/components/team/TeamSettings.tsx b/apps/web/components/team/TeamSettings.tsx deleted file mode 100644 index 297d465a46..0000000000 --- a/apps/web/components/team/TeamSettings.tsx +++ /dev/null @@ -1,212 +0,0 @@ -import React, { useRef, useState } from "react"; - -import { APP_NAME } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { objectKeys } from "@calcom/lib/objectKeys"; -import { TeamWithMembers } from "@calcom/lib/server/queries/teams"; -import { trpc } from "@calcom/trpc/react"; -import { Alert, Button, Icon, showToast, TextField } from "@calcom/ui"; - -import ImageUploader from "@components/ImageUploader"; -import SettingInputContainer from "@components/ui/SettingInputContainer"; - -interface Props { - team: TeamWithMembers | null | undefined; -} - -export default function TeamSettings(props: Props) { - const { t } = useLocale(); - - const [hasErrors, setHasErrors] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - const team = props.team; - const hasLogo = !!team?.logo; - - const utils = trpc.useContext(); - const mutation = trpc.viewer.teams.update.useMutation({ - onError: (err) => { - setHasErrors(true); - setErrorMessage(err.message); - }, - async onSuccess() { - await utils.viewer.teams.get.invalidate(); - showToast(t("your_team_updated_successfully"), "success"); - setHasErrors(false); - }, - }); - - const nameRef = useRef() as React.MutableRefObject; - const teamUrlRef = useRef() as React.MutableRefObject; - const descriptionRef = useRef() as React.MutableRefObject; - const hideBrandingRef = useRef() as React.MutableRefObject; - const logoRef = useRef() as React.MutableRefObject; - - function updateTeamData() { - if (!team) return; - const variables = { - name: nameRef.current?.value, - slug: teamUrlRef.current?.value, - bio: descriptionRef.current?.value, - hideBranding: hideBrandingRef.current?.checked, - }; - // remove unchanged variables - objectKeys(variables).forEach((key) => { - if (variables[key as keyof typeof variables] === team?.[key]) delete variables[key]; - }); - mutation.mutate({ id: team.id, ...variables }); - } - - function updateLogo(newLogo: string) { - if (!team) return; - logoRef.current.value = newLogo; - mutation.mutate({ id: team.id, logo: newLogo }); - } - - const removeLogo = () => updateLogo(""); - - return ( -
-
- {hasErrors && } -
{ - e.preventDefault(); - updateTeamData(); - }}> -
-
-
- - {process.env.NEXT_PUBLIC_WEBSITE_URL}/team/ - - } - ref={teamUrlRef} - defaultValue={team?.slug as string} - /> - } - /> - - } - /> -
-
- -