diff --git a/apps/web/components/AdditionalCalendarSelector.tsx b/apps/web/components/AdditionalCalendarSelector.tsx index 192aff0df2..dbeab7cb8e 100644 --- a/apps/web/components/AdditionalCalendarSelector.tsx +++ b/apps/web/components/AdditionalCalendarSelector.tsx @@ -4,11 +4,11 @@ import { OptionProps } from "react-select"; import { InstallAppButton } from "@calcom/app-store/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import type { App } from "@calcom/types/App"; import { Button } from "@calcom/ui"; import { QueryCell } from "@lib/QueryCell"; -import { trpc } from "@lib/trpc"; interface AdditionalCalendarSelectorProps { isLoading?: boolean; diff --git a/apps/web/components/App.tsx b/apps/web/components/App.tsx index 5704f2df57..98f1b7f25f 100644 --- a/apps/web/components/App.tsx +++ b/apps/web/components/App.tsx @@ -16,12 +16,11 @@ import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation"; import { InstallAppButton } from "@calcom/app-store/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { App as AppType } from "@calcom/types/App"; import { Button, SkeletonButton } from "@calcom/ui"; import LicenseRequired from "@ee/components/LicenseRequired"; -import { trpc } from "@lib/trpc"; - import Shell from "@components/Shell"; import Badge from "@components/ui/Badge"; diff --git a/apps/web/components/DestinationCalendarSelector.tsx b/apps/web/components/DestinationCalendarSelector.tsx index 25f4a7f5ac..d459a03c93 100644 --- a/apps/web/components/DestinationCalendarSelector.tsx +++ b/apps/web/components/DestinationCalendarSelector.tsx @@ -3,8 +3,7 @@ import React, { useEffect, useState } from "react"; import Select from "react-select"; import { useLocale } from "@calcom/lib/hooks/useLocale"; - -import { trpc } from "@lib/trpc"; +import { trpc } from "@calcom/trpc/react"; interface Props { onChange: (value: { externalId: string; integration: string }) => void; diff --git a/apps/web/components/Embed.tsx b/apps/web/components/Embed.tsx index 736931db18..cc4c8fdc3d 100644 --- a/apps/web/components/Embed.tsx +++ b/apps/web/components/Embed.tsx @@ -8,12 +8,12 @@ import { components, ControlProps } from "react-select"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { EventType } from "@calcom/prisma/client"; +import { trpc } from "@calcom/trpc/react"; import { Button, Switch } from "@calcom/ui"; import { Dialog, DialogClose, DialogContent } from "@calcom/ui/Dialog"; import { InputLeading, Label, TextArea, TextField } from "@calcom/ui/form/fields"; import { EMBED_LIB_URL, WEBAPP_URL } from "@lib/config/constants"; -import { trpc } from "@lib/trpc"; import NavTabs from "@components/NavTabs"; import ColorPicker from "@components/ui/colorpicker"; diff --git a/apps/web/components/I18nLanguageHandler.tsx b/apps/web/components/I18nLanguageHandler.tsx index 1a78b6557e..c4c7d2070e 100644 --- a/apps/web/components/I18nLanguageHandler.tsx +++ b/apps/web/components/I18nLanguageHandler.tsx @@ -1,7 +1,7 @@ import { useTranslation } from "next-i18next"; import { useEffect } from "react"; -import { trpc } from "@lib/trpc"; +import { trpc } from "@calcom/trpc/react"; export function useViewerI18n() { return trpc.useQuery(["viewer.public.i18n"], { diff --git a/apps/web/components/Shell.tsx b/apps/web/components/Shell.tsx index 9c1a2be08a..6eee53d45c 100644 --- a/apps/web/components/Shell.tsx +++ b/apps/web/components/Shell.tsx @@ -24,6 +24,7 @@ import { Toaster } from "react-hot-toast"; import { useIsEmbed } from "@calcom/embed-core/embed-iframe"; import { WEBAPP_URL, JOIN_SLACK, ROADMAP } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import Dropdown, { DropdownMenuContent, @@ -39,7 +40,6 @@ import ErrorBoundary from "@lib/ErrorBoundary"; import classNames from "@lib/classNames"; import { shouldShowOnboarding } from "@lib/getting-started"; import useMeQuery from "@lib/hooks/useMeQuery"; -import { trpc } from "@lib/trpc"; import CustomBranding from "@components/CustomBranding"; import { KBarRoot, KBarContent, KBarTrigger } from "@components/Kbar"; diff --git a/apps/web/components/apps/AppCard.tsx b/apps/web/components/apps/AppCard.tsx index c6a6ee17f4..6397b9e46b 100644 --- a/apps/web/components/apps/AppCard.tsx +++ b/apps/web/components/apps/AppCard.tsx @@ -1,9 +1,8 @@ import Link from "next/link"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; -import { trpc } from "@lib/trpc"; - import Badge from "@components/ui/Badge"; interface AppCardProps { diff --git a/apps/web/components/auth/SAMLLogin.tsx b/apps/web/components/auth/SAMLLogin.tsx index 76f7c75c8c..62ec48ef0f 100644 --- a/apps/web/components/auth/SAMLLogin.tsx +++ b/apps/web/components/auth/SAMLLogin.tsx @@ -2,11 +2,11 @@ import { signIn } from "next-auth/react"; import { Dispatch, SetStateAction } from "react"; import { useFormContext } from "react-hook-form"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { useLocale } from "@lib/hooks/useLocale"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; -import { trpc } from "@lib/trpc"; interface Props { email: string; diff --git a/apps/web/components/availability/NewScheduleButton.tsx b/apps/web/components/availability/NewScheduleButton.tsx index 1d1fc7ae30..b0f591b466 100644 --- a/apps/web/components/availability/NewScheduleButton.tsx +++ b/apps/web/components/availability/NewScheduleButton.tsx @@ -4,12 +4,12 @@ import { useForm } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui/Dialog"; import { Form } from "@calcom/ui/form/fields"; import { HttpError } from "@lib/core/http/error"; -import { trpc } from "@lib/trpc"; export function NewScheduleButton({ name = "new-schedule" }: { name?: string }) { const router = useRouter(); diff --git a/apps/web/components/availability/ScheduleListItem.tsx b/apps/web/components/availability/ScheduleListItem.tsx index 74f759563b..e498b1f8f4 100644 --- a/apps/web/components/availability/ScheduleListItem.tsx +++ b/apps/web/components/availability/ScheduleListItem.tsx @@ -5,11 +5,10 @@ import { Fragment } from "react"; import { availabilityAsString } from "@calcom/lib/availability"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Availability } from "@calcom/prisma/client"; +import { inferQueryOutput } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@calcom/ui/Dropdown"; -import { inferQueryOutput } from "@lib/trpc"; - export function ScheduleListItem({ schedule, deleteFunction, diff --git a/apps/web/components/booking/AvailableTimes.tsx b/apps/web/components/booking/AvailableTimes.tsx index e80afaae5c..1d0273b92c 100644 --- a/apps/web/components/booking/AvailableTimes.tsx +++ b/apps/web/components/booking/AvailableTimes.tsx @@ -6,13 +6,12 @@ import { FC, useEffect, useState } from "react"; import dayjs, { Dayjs } from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { nameOfDay } from "@calcom/lib/weekday"; +import type { Slot } from "@calcom/trpc/server/routers/viewer/slots"; import { SkeletonContainer, SkeletonText } from "@calcom/ui"; import classNames from "@lib/classNames"; import { timeZone } from "@lib/clock"; -import type { Slot } from "@server/routers/viewer/slots"; - type AvailableTimesProps = { timeFormat: string; eventTypeId: number; diff --git a/apps/web/components/booking/BookingListItem.tsx b/apps/web/components/booking/BookingListItem.tsx index e562feb378..65861d1cc3 100644 --- a/apps/web/components/booking/BookingListItem.tsx +++ b/apps/web/components/booking/BookingListItem.tsx @@ -18,6 +18,7 @@ import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { getEveryFreqFor } from "@calcom/lib/recurringStrings"; +import { inferQueryInput, inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog"; import { Tooltip } from "@calcom/ui/Tooltip"; @@ -28,7 +29,6 @@ import useMeQuery from "@lib/hooks/useMeQuery"; import { linkValueToString } from "@lib/linkValueToString"; import { LocationType } from "@lib/location"; import { extractRecurringDates } from "@lib/parseDate"; -import { inferQueryInput, inferQueryOutput, trpc } from "@lib/trpc"; import { EditLocationDialog } from "@components/dialog/EditLocationDialog"; import { RescheduleDialog } from "@components/dialog/RescheduleDialog"; diff --git a/apps/web/components/booking/pages/AvailabilityPage.tsx b/apps/web/components/booking/pages/AvailabilityPage.tsx index 8010f2565f..dc26259084 100644 --- a/apps/web/components/booking/pages/AvailabilityPage.tsx +++ b/apps/web/components/booking/pages/AvailabilityPage.tsx @@ -35,6 +35,7 @@ import { CAL_URL, WEBSITE_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { getRecurringFreq } from "@calcom/lib/recurringStrings"; import { localStorage } from "@calcom/lib/webstorage"; +import { trpc } from "@calcom/trpc/react"; import DatePicker from "@calcom/ui/booker/DatePicker"; import { timeZone as localStorageTimeZone } from "@lib/clock"; @@ -44,7 +45,6 @@ import useTheme from "@lib/hooks/useTheme"; import { isBrandingHidden } from "@lib/isBrandingHidden"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; import { detectBrowserTimeFormat } from "@lib/timeFormat"; -import { trpc } from "@lib/trpc"; import CustomBranding from "@components/CustomBranding"; import AvailableTimes from "@components/booking/AvailableTimes"; diff --git a/apps/web/components/dialog/EditLocationDialog.tsx b/apps/web/components/dialog/EditLocationDialog.tsx index f96668703c..94233f49f8 100644 --- a/apps/web/components/dialog/EditLocationDialog.tsx +++ b/apps/web/components/dialog/EditLocationDialog.tsx @@ -8,6 +8,7 @@ import { z } from "zod"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Dialog, DialogContent } from "@calcom/ui/Dialog"; import { Form } from "@calcom/ui/form/fields"; @@ -16,7 +17,6 @@ import { QueryCell } from "@lib/QueryCell"; import { linkValueToString } from "@lib/linkValueToString"; import { LocationType } from "@lib/location"; import { LocationOptionsToString } from "@lib/locationOptions"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import CheckboxField from "@components/ui/form/CheckboxField"; import type PhoneInputType from "@components/ui/form/PhoneInput"; diff --git a/apps/web/components/dialog/RescheduleDialog.tsx b/apps/web/components/dialog/RescheduleDialog.tsx index 7e11fbf453..60aa8afc60 100644 --- a/apps/web/components/dialog/RescheduleDialog.tsx +++ b/apps/web/components/dialog/RescheduleDialog.tsx @@ -5,12 +5,12 @@ import { useMutation } from "react-query"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog"; import { TextArea } from "@calcom/ui/form/fields"; import * as fetchWrapper from "@lib/core/http/fetch-wrapper"; -import { trpc } from "@lib/trpc"; interface IRescheduleDialog { isOpenDialog: boolean; diff --git a/apps/web/components/eventtype/CreateEventType.tsx b/apps/web/components/eventtype/CreateEventType.tsx index 6685879ce4..a8c9317a4c 100644 --- a/apps/web/components/eventtype/CreateEventType.tsx +++ b/apps/web/components/eventtype/CreateEventType.tsx @@ -10,6 +10,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { createEventTypeInput } from "@calcom/prisma/zod/custom/eventtype"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import { Button } from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent } from "@calcom/ui/Dialog"; @@ -24,7 +25,6 @@ import { Form, InputLeading, TextAreaField, TextField } from "@calcom/ui/form/fi import { HttpError } from "@lib/core/http/error"; import { slugify } from "@lib/slugify"; -import { trpc } from "@lib/trpc"; import Avatar from "@components/ui/Avatar"; import * as RadioArea from "@components/ui/form/radio-area"; diff --git a/apps/web/components/integrations/CalendarListContainer.tsx b/apps/web/components/integrations/CalendarListContainer.tsx index ffb1819f0c..55fc7d00e4 100644 --- a/apps/web/components/integrations/CalendarListContainer.tsx +++ b/apps/web/components/integrations/CalendarListContainer.tsx @@ -4,12 +4,12 @@ import { useMutation } from "react-query"; import { InstallAppButton } from "@calcom/app-store/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import Switch from "@calcom/ui/Switch"; import { QueryCell } from "@lib/QueryCell"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import AdditionalCalendarSelector from "@components/AdditionalCalendarSelector"; import DestinationCalendarSelector from "@components/DestinationCalendarSelector"; diff --git a/apps/web/components/integrations/DisconnectIntegration.tsx b/apps/web/components/integrations/DisconnectIntegration.tsx index 9568aac277..ec74fea0b2 100644 --- a/apps/web/components/integrations/DisconnectIntegration.tsx +++ b/apps/web/components/integrations/DisconnectIntegration.tsx @@ -3,11 +3,10 @@ import { useMutation } from "react-query"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { ButtonBaseProps } from "@calcom/ui/Button"; import { Dialog } from "@calcom/ui/Dialog"; -import { trpc } from "@lib/trpc"; - import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; export default function DisconnectIntegration(props: { diff --git a/apps/web/components/security/DisableUserImpersonation.tsx b/apps/web/components/security/DisableUserImpersonation.tsx index c17d114ce7..79b1f297c4 100644 --- a/apps/web/components/security/DisableUserImpersonation.tsx +++ b/apps/web/components/security/DisableUserImpersonation.tsx @@ -1,9 +1,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; -import { trpc } from "@lib/trpc"; - import Badge from "@components/ui/Badge"; const DisableUserImpersonation = ({ disableImpersonation }: { disableImpersonation: boolean }) => { diff --git a/apps/web/components/team/DisableTeamImpersonation.tsx b/apps/web/components/team/DisableTeamImpersonation.tsx index 1e1065f8b0..d1b75b5f7c 100644 --- a/apps/web/components/team/DisableTeamImpersonation.tsx +++ b/apps/web/components/team/DisableTeamImpersonation.tsx @@ -1,9 +1,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; -import { trpc } from "@lib/trpc"; - import Badge from "@components/ui/Badge"; const DisableTeamImpersonation = ({ teamId, memberId }: { teamId: number; memberId: number }) => { diff --git a/apps/web/components/team/MemberChangeRoleModal.tsx b/apps/web/components/team/MemberChangeRoleModal.tsx index 263cd3d968..642675bc7c 100644 --- a/apps/web/components/team/MemberChangeRoleModal.tsx +++ b/apps/web/components/team/MemberChangeRoleModal.tsx @@ -2,10 +2,9 @@ import { MembershipRole } from "@prisma/client"; import { SyntheticEvent, useMemo, useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; -import { trpc } from "@lib/trpc"; - import ModalContainer from "@components/ui/ModalContainer"; import Select from "@components/ui/form/Select"; diff --git a/apps/web/components/team/MemberInvitationModal.tsx b/apps/web/components/team/MemberInvitationModal.tsx index 7d7495d398..2ead04d2d9 100644 --- a/apps/web/components/team/MemberInvitationModal.tsx +++ b/apps/web/components/team/MemberInvitationModal.tsx @@ -3,13 +3,13 @@ import { InformationCircleIcon } from "@heroicons/react/solid"; import { MembershipRole } from "@prisma/client"; import React, { useState, SyntheticEvent, useMemo } from "react"; +import { TeamWithMembers } from "@calcom/lib/server/queries/teams"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog"; import { TextField } from "@calcom/ui/form/fields"; import { useLocale } from "@lib/hooks/useLocale"; -import { TeamWithMembers } from "@lib/queries/teams"; -import { trpc } from "@lib/trpc"; import Select from "@components/ui/form/Select"; diff --git a/apps/web/components/team/MemberList.tsx b/apps/web/components/team/MemberList.tsx index 0d41d4d693..24cf37ebe7 100644 --- a/apps/web/components/team/MemberList.tsx +++ b/apps/web/components/team/MemberList.tsx @@ -1,4 +1,4 @@ -import { inferQueryOutput } from "@lib/trpc"; +import { inferQueryOutput } from "@calcom/trpc/react"; import MemberListItem from "./MemberListItem"; diff --git a/apps/web/components/team/MemberListItem.tsx b/apps/web/components/team/MemberListItem.tsx index 952308e3bd..18ee2496e8 100644 --- a/apps/web/components/team/MemberListItem.tsx +++ b/apps/web/components/team/MemberListItem.tsx @@ -8,6 +8,7 @@ import { useState } from "react"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import Dropdown, { @@ -20,7 +21,6 @@ import { Tooltip } from "@calcom/ui/Tooltip"; import TeamAvailabilityModal from "@ee/components/team/availability/TeamAvailabilityModal"; import useCurrentUserId from "@lib/hooks/useCurrentUserId"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import Avatar from "@components/ui/Avatar"; diff --git a/apps/web/components/team/TeamCreateModal.tsx b/apps/web/components/team/TeamCreateModal.tsx index b96ae5a804..1c0189cac3 100644 --- a/apps/web/components/team/TeamCreateModal.tsx +++ b/apps/web/components/team/TeamCreateModal.tsx @@ -2,12 +2,11 @@ import { UsersIcon } from "@heroicons/react/outline"; import { useRef, useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Alert } from "@calcom/ui/Alert"; import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog"; -import { trpc } from "@lib/trpc"; - interface Props { isOpen: boolean; onClose: () => void; diff --git a/apps/web/components/team/TeamList.tsx b/apps/web/components/team/TeamList.tsx index f817770042..fdb9466f72 100644 --- a/apps/web/components/team/TeamList.tsx +++ b/apps/web/components/team/TeamList.tsx @@ -1,6 +1,5 @@ import showToast from "@calcom/lib/notification"; - -import { inferQueryOutput, trpc } from "@lib/trpc"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import TeamListItem from "./TeamListItem"; diff --git a/apps/web/components/team/TeamListItem.tsx b/apps/web/components/team/TeamListItem.tsx index 57482bffe0..a6901fa40b 100644 --- a/apps/web/components/team/TeamListItem.tsx +++ b/apps/web/components/team/TeamListItem.tsx @@ -13,6 +13,7 @@ import Link from "next/link"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import Dropdown, { @@ -25,7 +26,6 @@ import { Tooltip } from "@calcom/ui/Tooltip"; import classNames from "@lib/classNames"; import { getPlaceholderAvatar } from "@lib/getPlaceholderAvatar"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import Avatar from "@components/ui/Avatar"; diff --git a/apps/web/components/team/TeamSettings.tsx b/apps/web/components/team/TeamSettings.tsx index 16f81c94ee..d1134e7f62 100644 --- a/apps/web/components/team/TeamSettings.tsx +++ b/apps/web/components/team/TeamSettings.tsx @@ -4,13 +4,12 @@ import React, { useRef, useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { objectKeys } from "@calcom/lib/objectKeys"; +import { TeamWithMembers } from "@calcom/lib/server/queries/teams"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import { TextField } from "@calcom/ui/form/fields"; -import { TeamWithMembers } from "@lib/queries/teams"; -import { trpc } from "@lib/trpc"; - import ImageUploader from "@components/ImageUploader"; import SettingInputContainer from "@components/ui/SettingInputContainer"; diff --git a/apps/web/components/team/TeamSettingsRightSidebar.tsx b/apps/web/components/team/TeamSettingsRightSidebar.tsx index e4c857f595..420c153594 100644 --- a/apps/web/components/team/TeamSettingsRightSidebar.tsx +++ b/apps/web/components/team/TeamSettingsRightSidebar.tsx @@ -5,11 +5,11 @@ import { useRouter } from "next/router"; import React from "react"; import showToast from "@calcom/lib/notification"; +import { TeamWithMembers } from "@calcom/lib/server/queries/teams"; +import { trpc } from "@calcom/trpc/react"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import { useLocale } from "@lib/hooks/useLocale"; -import { TeamWithMembers } from "@lib/queries/teams"; -import { trpc } from "@lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import CreateEventTypeButton from "@components/eventtype/CreateEventType"; diff --git a/apps/web/components/team/UpgradeToFlexibleProModal.tsx b/apps/web/components/team/UpgradeToFlexibleProModal.tsx index 19ec8d3925..34e19e5714 100644 --- a/apps/web/components/team/UpgradeToFlexibleProModal.tsx +++ b/apps/web/components/team/UpgradeToFlexibleProModal.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import { @@ -13,7 +14,6 @@ import { } from "@calcom/ui/Dialog"; import { useLocale } from "@lib/hooks/useLocale"; -import { trpc } from "@lib/trpc"; interface Props { teamId: number; diff --git a/apps/web/components/ui/Avatar.tsx b/apps/web/components/ui/Avatar.tsx index d20056d095..44373297f7 100644 --- a/apps/web/components/ui/Avatar.tsx +++ b/apps/web/components/ui/Avatar.tsx @@ -1,11 +1,11 @@ import * as AvatarPrimitive from "@radix-ui/react-avatar"; import * as Tooltip from "@radix-ui/react-tooltip"; +import { Maybe } from "@calcom/trpc/server"; + import classNames from "@lib/classNames"; import { defaultAvatarSrc } from "@lib/profile"; -import { Maybe } from "@trpc/server"; - export type AvatarProps = { className?: string; size?: number; diff --git a/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx b/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx index 6044eac72c..685c662c6f 100644 --- a/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx +++ b/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx @@ -7,15 +7,13 @@ import { fetchUsername } from "@calcom/lib/fetchUsername"; import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { User } from "@calcom/prisma/client"; +import { TRPCClientErrorLike } from "@calcom/trpc/client"; +import { trpc } from "@calcom/trpc/react"; +import type { AppRouter } from "@calcom/trpc/server/routers/_app"; import Button from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog"; import { Input, Label } from "@calcom/ui/form/fields"; -import { trpc } from "@lib/trpc"; - -import { AppRouter } from "@server/routers/_app"; -import { TRPCClientErrorLike } from "@trpc/client"; - export enum UsernameChangeStatusEnum { NORMAL = "NORMAL", UPGRADE = "UPGRADE", diff --git a/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx b/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx index 325647f3be..3971f92f56 100644 --- a/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx +++ b/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx @@ -5,15 +5,13 @@ import { MutableRefObject, useCallback, useEffect, useState } from "react"; import { fetchUsername } from "@calcom/lib/fetchUsername"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { TRPCClientErrorLike } from "@calcom/trpc/client"; +import { trpc } from "@calcom/trpc/react"; +import { AppRouter } from "@calcom/trpc/server/routers/_app"; import Button from "@calcom/ui/Button"; import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog"; import { Input, Label } from "@calcom/ui/form/fields"; -import { trpc } from "@lib/trpc"; - -import { AppRouter } from "@server/routers/_app"; -import { TRPCClientErrorLike } from "@trpc/client"; - interface ICustomUsernameProps { currentUsername: string | undefined; setCurrentUsername: (value: string | undefined) => void; diff --git a/apps/web/components/webhook/WebhookDialogForm.tsx b/apps/web/components/webhook/WebhookDialogForm.tsx index 4ca59e5c6b..6773e9b649 100644 --- a/apps/web/components/webhook/WebhookDialogForm.tsx +++ b/apps/web/components/webhook/WebhookDialogForm.tsx @@ -3,12 +3,12 @@ import { Controller, useForm } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { DialogFooter } from "@calcom/ui/Dialog"; import Switch from "@calcom/ui/Switch"; import { FieldsetLegend, Form, InputGroupBox, TextArea, TextField } from "@calcom/ui/form/fields"; -import { trpc } from "@lib/trpc"; import { WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP } from "@lib/webhooks/constants"; import customTemplate, { hasTemplateIntegration } from "@lib/webhooks/integrationTemplate"; diff --git a/apps/web/components/webhook/WebhookListContainer.tsx b/apps/web/components/webhook/WebhookListContainer.tsx index 85fb600a1c..ba5c95ae03 100644 --- a/apps/web/components/webhook/WebhookListContainer.tsx +++ b/apps/web/components/webhook/WebhookListContainer.tsx @@ -1,11 +1,11 @@ import { PlusIcon } from "@heroicons/react/solid"; import { useState } from "react"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogContent } from "@calcom/ui/Dialog"; import { QueryCell } from "@lib/QueryCell"; -import { trpc } from "@lib/trpc"; import { List } from "@components/List"; import { ShellSubHeading } from "@components/Shell"; diff --git a/apps/web/components/webhook/WebhookListItem.tsx b/apps/web/components/webhook/WebhookListItem.tsx index 4f16386656..fdf77a9265 100644 --- a/apps/web/components/webhook/WebhookListItem.tsx +++ b/apps/web/components/webhook/WebhookListItem.tsx @@ -1,12 +1,12 @@ import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline"; import classNames from "@calcom/lib/classNames"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import { Tooltip } from "@calcom/ui/Tooltip"; import { useLocale } from "@lib/hooks/useLocale"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import { ListItem } from "@components/List"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; diff --git a/apps/web/components/webhook/WebhookTestDisclosure.tsx b/apps/web/components/webhook/WebhookTestDisclosure.tsx index ffd94db8e9..7fd419916b 100644 --- a/apps/web/components/webhook/WebhookTestDisclosure.tsx +++ b/apps/web/components/webhook/WebhookTestDisclosure.tsx @@ -5,11 +5,11 @@ import { useWatch } from "react-hook-form"; import classNames from "@calcom/lib/classNames"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { InputGroupBox } from "@calcom/ui/form/fields"; import { useLocale } from "@lib/hooks/useLocale"; -import { trpc } from "@lib/trpc"; export default function WebhookTestDisclosure() { const subscriberUrl: string = useWatch({ name: "subscriberUrl" }); diff --git a/apps/web/ee/components/apiKeys/ApiKeyDialogForm.tsx b/apps/web/ee/components/apiKeys/ApiKeyDialogForm.tsx index 370d8e7c7a..9a6b0b6ab0 100644 --- a/apps/web/ee/components/apiKeys/ApiKeyDialogForm.tsx +++ b/apps/web/ee/components/apiKeys/ApiKeyDialogForm.tsx @@ -5,14 +5,13 @@ import { Controller, useForm } from "react-hook-form"; import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { DialogFooter } from "@calcom/ui/Dialog"; import Switch from "@calcom/ui/Switch"; import { Tooltip } from "@calcom/ui/Tooltip"; import { Form, TextField } from "@calcom/ui/form/fields"; -import { trpc } from "@lib/trpc"; - import { DatePicker } from "@components/ui/form/DatePicker"; import LicenseRequired from "../LicenseRequired"; diff --git a/apps/web/ee/components/apiKeys/ApiKeyListContainer.tsx b/apps/web/ee/components/apiKeys/ApiKeyListContainer.tsx index 47fedac8da..219eaca433 100644 --- a/apps/web/ee/components/apiKeys/ApiKeyListContainer.tsx +++ b/apps/web/ee/components/apiKeys/ApiKeyListContainer.tsx @@ -2,13 +2,13 @@ import { PlusIcon } from "@heroicons/react/outline"; import { useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogContent } from "@calcom/ui/Dialog"; import ApiKeyDialogForm from "@ee/components/apiKeys/ApiKeyDialogForm"; import ApiKeyListItem, { TApiKeys } from "@ee/components/apiKeys/ApiKeyListItem"; import { QueryCell } from "@lib/QueryCell"; -import { trpc } from "@lib/trpc"; import { List } from "@components/List"; import { ShellSubHeading } from "@components/Shell"; diff --git a/apps/web/ee/components/apiKeys/ApiKeyListItem.tsx b/apps/web/ee/components/apiKeys/ApiKeyListItem.tsx index 81ac3ec46e..c1c6a1c6b2 100644 --- a/apps/web/ee/components/apiKeys/ApiKeyListItem.tsx +++ b/apps/web/ee/components/apiKeys/ApiKeyListItem.tsx @@ -4,12 +4,11 @@ import { ExclamationIcon } from "@heroicons/react/solid"; import dayjs from "@calcom/dayjs"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import { Tooltip } from "@calcom/ui/Tooltip"; -import { inferQueryOutput, trpc } from "@lib/trpc"; - import { ListItem } from "@components/List"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import Badge from "@components/ui/Badge"; diff --git a/apps/web/ee/components/saml/Configuration.tsx b/apps/web/ee/components/saml/Configuration.tsx index 7778b647da..d2e4fe34d3 100644 --- a/apps/web/ee/components/saml/Configuration.tsx +++ b/apps/web/ee/components/saml/Configuration.tsx @@ -2,13 +2,13 @@ import React, { useEffect, useRef, useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import { TextArea } from "@calcom/ui/form/fields"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; -import { trpc } from "@lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import Badge from "@components/ui/Badge"; diff --git a/apps/web/ee/components/support/HelpMenuItem.tsx b/apps/web/ee/components/support/HelpMenuItem.tsx index 757b71db2e..25f0231034 100644 --- a/apps/web/ee/components/support/HelpMenuItem.tsx +++ b/apps/web/ee/components/support/HelpMenuItem.tsx @@ -4,10 +4,10 @@ import { HelpScout, useChat } from "react-live-chat-loader"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import classNames from "@lib/classNames"; -import { trpc } from "@lib/trpc"; import ContactMenuItem from "./ContactMenuItem"; diff --git a/apps/web/ee/components/team/availability/TeamAvailabilityModal.tsx b/apps/web/ee/components/team/availability/TeamAvailabilityModal.tsx index 35308514a5..70cdc4bb7f 100644 --- a/apps/web/ee/components/team/availability/TeamAvailabilityModal.tsx +++ b/apps/web/ee/components/team/availability/TeamAvailabilityModal.tsx @@ -2,10 +2,9 @@ import React, { useState, useEffect } from "react"; import dayjs from "@calcom/dayjs"; import { WEBAPP_URL } from "@calcom/lib/constants"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import LicenseRequired from "@ee/components/LicenseRequired"; -import { inferQueryOutput, trpc } from "@lib/trpc"; - import Avatar from "@components/ui/Avatar"; import { DatePicker } from "@components/ui/form/DatePicker"; import Select from "@components/ui/form/Select"; diff --git a/apps/web/ee/components/team/availability/TeamAvailabilityScreen.tsx b/apps/web/ee/components/team/availability/TeamAvailabilityScreen.tsx index 55ae53e831..763a9da339 100644 --- a/apps/web/ee/components/team/availability/TeamAvailabilityScreen.tsx +++ b/apps/web/ee/components/team/availability/TeamAvailabilityScreen.tsx @@ -4,8 +4,7 @@ import { FixedSizeList as List } from "react-window"; import dayjs from "@calcom/dayjs"; import { CAL_URL } from "@calcom/lib/constants"; - -import { inferQueryOutput, trpc } from "@lib/trpc"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Avatar from "@components/ui/Avatar"; import { DatePicker } from "@components/ui/form/DatePicker"; diff --git a/apps/web/ee/components/team/availability/TeamAvailabilityTimes.tsx b/apps/web/ee/components/team/availability/TeamAvailabilityTimes.tsx index f89aff6718..601ed1e0c6 100644 --- a/apps/web/ee/components/team/availability/TeamAvailabilityTimes.tsx +++ b/apps/web/ee/components/team/availability/TeamAvailabilityTimes.tsx @@ -3,9 +3,8 @@ import React from "react"; import { ITimezone } from "react-timezone-select"; import { Dayjs } from "@calcom/dayjs"; - -import getSlots from "@lib/slots"; -import { trpc } from "@lib/trpc"; +import getSlots from "@calcom/lib/slots"; +import { trpc } from "@calcom/trpc/react"; import Loader from "@components/Loader"; diff --git a/apps/web/ee/components/workflows/NewWorkflowButton.tsx b/apps/web/ee/components/workflows/NewWorkflowButton.tsx index b62d7355bb..5840e96c05 100644 --- a/apps/web/ee/components/workflows/NewWorkflowButton.tsx +++ b/apps/web/ee/components/workflows/NewWorkflowButton.tsx @@ -9,6 +9,7 @@ import { z } from "zod"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui/Dialog"; import { Form, TextField } from "@calcom/ui/form/fields"; @@ -20,7 +21,6 @@ import { } from "@ee/lib/workflows/getOptions"; import { HttpError } from "@lib/core/http/error"; -import { trpc } from "@lib/trpc"; import PhoneInput from "@components/ui/form/PhoneInput"; import Select from "@components/ui/form/Select"; diff --git a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx index 51659d6762..b936a201ef 100644 --- a/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx +++ b/apps/web/ee/components/workflows/WorkflowDetailsPage.tsx @@ -6,14 +6,13 @@ import { Controller, UseFormReturn } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { HttpError } from "@calcom/lib/http-error"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; 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 { FormValues } from "@ee/pages/workflows/[workflow]"; -import { trpc } from "@lib/trpc"; - import MultiSelectCheckboxes, { Option } from "@components/ui/form/MultiSelectCheckboxes"; interface Props { diff --git a/apps/web/ee/components/workflows/WorkflowListPage.tsx b/apps/web/ee/components/workflows/WorkflowListPage.tsx index c04cd19b8f..db865c4cb5 100644 --- a/apps/web/ee/components/workflows/WorkflowListPage.tsx +++ b/apps/web/ee/components/workflows/WorkflowListPage.tsx @@ -6,13 +6,13 @@ import { useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { EventType, Workflow, WorkflowsOnEventTypes } from "@calcom/prisma/client"; +import { trpc } from "@calcom/trpc/react"; import { Button, Tooltip } from "@calcom/ui"; import { Dialog } from "@calcom/ui/Dialog"; import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@calcom/ui/Dropdown"; import EmptyScreen from "@calcom/ui/EmptyScreen"; import { HttpError } from "@lib/core/http/error"; -import { trpc } from "@lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; diff --git a/apps/web/ee/lib/stripe/server.ts b/apps/web/ee/lib/stripe/server.ts deleted file mode 100644 index 6796946bb0..0000000000 --- a/apps/web/ee/lib/stripe/server.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { PaymentType, Prisma } from "@prisma/client"; -import Stripe from "stripe"; -import { v4 as uuidv4 } from "uuid"; -import { z } from "zod"; - -import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug"; -import { sendAwaitingPaymentEmail, sendOrganizerPaymentRefundFailedEmail } from "@calcom/emails"; -import { getErrorFromUnknown } from "@calcom/lib/errors"; -import prisma from "@calcom/prisma"; -import { createPaymentLink } from "@calcom/stripe/client"; -import stripe, { PaymentData } from "@calcom/stripe/server"; -import { CalendarEvent } from "@calcom/types/Calendar"; - -const stripeKeysSchema = z.object({ - payment_fee_fixed: z.number(), - payment_fee_percentage: z.number(), -}); - -const stripeCredentialSchema = z.object({ - stripe_user_id: z.string(), - stripe_publishable_key: z.string(), -}); - -export async function handlePayment( - evt: CalendarEvent, - selectedEventType: { - price: number; - currency: string; - }, - stripeCredential: { key: Prisma.JsonValue }, - booking: { - user: { email: string | null; name: string | null; timeZone: string } | null; - id: number; - startTime: { toISOString: () => string }; - uid: string; - } -) { - const appKeys = await getAppKeysFromSlug("stripe"); - const { payment_fee_fixed, payment_fee_percentage } = stripeKeysSchema.parse(appKeys); - - const paymentFee = Math.round(selectedEventType.price * payment_fee_percentage + payment_fee_fixed); - const { stripe_user_id, stripe_publishable_key } = stripeCredentialSchema.parse(stripeCredential.key); - - const params: Stripe.PaymentIntentCreateParams = { - amount: selectedEventType.price, - currency: selectedEventType.currency, - payment_method_types: ["card"], - application_fee_amount: paymentFee, - }; - - const paymentIntent = await stripe.paymentIntents.create(params, { stripeAccount: stripe_user_id }); - - const payment = await prisma.payment.create({ - data: { - type: PaymentType.STRIPE, - uid: uuidv4(), - booking: { - connect: { - id: booking.id, - }, - }, - amount: selectedEventType.price, - fee: paymentFee, - currency: selectedEventType.currency, - success: false, - refunded: false, - data: Object.assign({}, paymentIntent, { - stripe_publishable_key, - stripeAccount: stripe_user_id, - }) /* We should treat this */ as PaymentData /* but Prisma doesn't know how to handle it, so it we treat it */ as unknown /* and then */ as Prisma.InputJsonValue, - externalId: paymentIntent.id, - }, - }); - - await sendAwaitingPaymentEmail({ - ...evt, - paymentInfo: { - link: createPaymentLink({ - paymentUid: payment.uid, - name: booking.user?.name, - email: booking.user?.email, - date: booking.startTime.toISOString(), - }), - }, - }); - - return payment; -} - -export async function refund( - booking: { - id: number; - uid: string; - startTime: Date; - payment: { - id: number; - success: boolean; - refunded: boolean; - externalId: string; - data: Prisma.JsonValue; - type: PaymentType; - }[]; - }, - calEvent: CalendarEvent -) { - try { - const payment = booking.payment.find((e) => e.success && !e.refunded); - if (!payment) return; - - if (payment.type !== PaymentType.STRIPE) { - await handleRefundError({ - event: calEvent, - reason: "cannot refund non Stripe payment", - paymentId: "unknown", - }); - return; - } - - const refund = await stripe.refunds.create( - { - payment_intent: payment.externalId, - }, - { stripeAccount: (payment.data as unknown as PaymentData)["stripeAccount"] } - ); - - if (!refund || refund.status === "failed") { - await handleRefundError({ - event: calEvent, - reason: refund?.failure_reason || "unknown", - paymentId: payment.externalId, - }); - return; - } - - await prisma.payment.update({ - where: { - id: payment.id, - }, - data: { - refunded: true, - }, - }); - } catch (e) { - const err = getErrorFromUnknown(e); - console.error(err, "Refund failed"); - await handleRefundError({ - event: calEvent, - reason: err.message || "unknown", - paymentId: "unknown", - }); - } -} - -export const closePayments = async (paymentIntentId: string, stripeAccount: string) => { - try { - // Expire all current sessions - const sessions = await stripe.checkout.sessions.list( - { - payment_intent: paymentIntentId, - }, - { stripeAccount } - ); - for (const session of sessions.data) { - await stripe.checkout.sessions.expire(session.id, { stripeAccount }); - } - // Then cancel the payment intent - await stripe.paymentIntents.cancel(paymentIntentId, { stripeAccount }); - return; - } catch (e) { - console.error(e); - return; - } -}; - -async function handleRefundError(opts: { event: CalendarEvent; reason: string; paymentId: string }) { - console.error(`refund failed: ${opts.reason} for booking '${opts.event.uid}'`); - await sendOrganizerPaymentRefundFailedEmail({ - ...opts.event, - paymentInfo: { reason: opts.reason, id: opts.paymentId }, - }); -} diff --git a/apps/web/ee/pages/settings/teams/[id]/availability.tsx b/apps/web/ee/pages/settings/teams/[id]/availability.tsx index 6b280f7337..13de941875 100644 --- a/apps/web/ee/pages/settings/teams/[id]/availability.tsx +++ b/apps/web/ee/pages/settings/teams/[id]/availability.tsx @@ -2,13 +2,13 @@ import { useRouter } from "next/router"; import { useMemo, useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import LicenseRequired from "@ee/components/LicenseRequired"; import TeamAvailabilityScreen from "@ee/components/team/availability/TeamAvailabilityScreen"; import { getPlaceholderAvatar } from "@lib/getPlaceholderAvatar"; import useMeQuery from "@lib/hooks/useMeQuery"; -import { trpc } from "@lib/trpc"; import Loader from "@components/Loader"; import Shell from "@components/Shell"; diff --git a/apps/web/ee/pages/workflows/[workflow].tsx b/apps/web/ee/pages/workflows/[workflow].tsx index 8da46fe82a..84adc3c819 100644 --- a/apps/web/ee/pages/workflows/[workflow].tsx +++ b/apps/web/ee/pages/workflows/[workflow].tsx @@ -9,6 +9,7 @@ import { useForm } from "react-hook-form"; import { z } from "zod"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Loader from "@calcom/ui/Loader"; import LicenseRequired from "@ee/components/LicenseRequired"; @@ -21,7 +22,6 @@ import { } from "@ee/lib/workflows/constants"; import useMeQuery from "@lib/hooks/useMeQuery"; -import { trpc } from "@lib/trpc"; import Shell from "@components/Shell"; import { Option } from "@components/ui/form/MultiSelectCheckboxes"; diff --git a/apps/web/ee/pages/workflows/index.tsx b/apps/web/ee/pages/workflows/index.tsx index a324eb6b3d..c3e075923b 100644 --- a/apps/web/ee/pages/workflows/index.tsx +++ b/apps/web/ee/pages/workflows/index.tsx @@ -1,13 +1,13 @@ import { useSession } from "next-auth/react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import LicenseRequired from "@ee/components/LicenseRequired"; import { NewWorkflowButton } from "@ee/components/workflows/NewWorkflowButton"; import WorkflowList from "@ee/components/workflows/WorkflowListPage"; import useMeQuery from "@lib/hooks/useMeQuery"; -import { trpc } from "@lib/trpc"; import Loader from "@components/Loader"; import Shell from "@components/Shell"; diff --git a/apps/web/lib/QueryCell.tsx b/apps/web/lib/QueryCell.tsx index 9918d2b3c3..b1ee6fa588 100644 --- a/apps/web/lib/QueryCell.tsx +++ b/apps/web/lib/QueryCell.tsx @@ -8,22 +8,19 @@ import { UseQueryResult, } from "react-query"; -import { Alert } from "@calcom/ui/Alert"; - -import { trpc } from "@lib/trpc"; - -import Loader from "@components/Loader"; - -import type { AppRouter } from "@server/routers/_app"; -import type { TRPCClientErrorLike } from "@trpc/client"; -import type { UseTRPCQueryOptions } from "@trpc/react"; -// import type { inferProcedures } from "@trpc/react/src/createReactQueryHooks"; +import type { TRPCClientErrorLike } from "@calcom/trpc/client"; +import { trpc } from "@calcom/trpc/react"; +import type { UseTRPCQueryOptions } from "@calcom/trpc/react"; import type { inferHandlerInput, inferProcedureInput, inferProcedureOutput, ProcedureRecord, -} from "@trpc/server"; +} from "@calcom/trpc/server"; +import type { AppRouter } from "@calcom/trpc/server/routers/_app"; +import { Alert } from "@calcom/ui/Alert"; + +import Loader from "@components/Loader"; type ErrorLike = { message: string; diff --git a/apps/web/lib/app-providers.tsx b/apps/web/lib/app-providers.tsx index 54b899002f..d5cf8226d8 100644 --- a/apps/web/lib/app-providers.tsx +++ b/apps/web/lib/app-providers.tsx @@ -1,15 +1,14 @@ import { SessionProvider } from "next-auth/react"; import { appWithTranslation } from "next-i18next"; import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app"; -import { ComponentProps, ReactNode, useMemo } from "react"; +import { ComponentProps, ReactNode } from "react"; +import { trpc } from "@calcom/trpc/react"; import DynamicHelpscoutProvider from "@ee/lib/helpscout/providerDynamic"; import DynamicIntercomProvider from "@ee/lib/intercom/providerDynamic"; import usePublicPage from "@lib/hooks/usePublicPage"; -import { trpc } from "./trpc"; - const I18nextAdapter = appWithTranslation(({ children }) => ( <>{children} )); diff --git a/apps/web/lib/core/i18n/i18n.utils.ts b/apps/web/lib/core/i18n/i18n.utils.ts index 1ba93e3d91..9899a5654e 100644 --- a/apps/web/lib/core/i18n/i18n.utils.ts +++ b/apps/web/lib/core/i18n/i18n.utils.ts @@ -1,11 +1,11 @@ import parser from "accept-language-parser"; import { IncomingMessage } from "http"; +import { Maybe } from "@calcom/trpc/server"; + import { getSession } from "@lib/auth"; import prisma from "@lib/prisma"; -import { Maybe } from "@trpc/server"; - import { i18n } from "../../../next-i18next.config"; export function getLocaleFromHeaders(req: IncomingMessage): string { diff --git a/apps/web/lib/hooks/useMeQuery.ts b/apps/web/lib/hooks/useMeQuery.ts index a8d0a051ce..0eb0bb77fd 100644 --- a/apps/web/lib/hooks/useMeQuery.ts +++ b/apps/web/lib/hooks/useMeQuery.ts @@ -1,4 +1,4 @@ -import { trpc } from "../trpc"; +import { trpc } from "@calcom/trpc/react"; export function useMeQuery() { const meQuery = trpc.useQuery(["viewer.me"], { diff --git a/apps/web/lib/hooks/useTheme.tsx b/apps/web/lib/hooks/useTheme.tsx index 38dc9f504b..d7891ba41d 100644 --- a/apps/web/lib/hooks/useTheme.tsx +++ b/apps/web/lib/hooks/useTheme.tsx @@ -2,8 +2,7 @@ import Head from "next/head"; import { useEffect, useState } from "react"; import { useEmbedTheme } from "@calcom/embed-core/embed-iframe"; - -import { Maybe } from "@trpc/server"; +import { Maybe } from "@calcom/trpc/server"; // This method is stringified and executed only on client. So, // - Pass all the params explicitly to this method. Don't use closure diff --git a/apps/web/lib/isOutOfBounds.tsx b/apps/web/lib/isOutOfBounds.tsx index 1a115f737d..d4d3bacbbc 100644 --- a/apps/web/lib/isOutOfBounds.tsx +++ b/apps/web/lib/isOutOfBounds.tsx @@ -1,41 +1,3 @@ -import { EventType, PeriodType } from "@prisma/client"; - -import dayjs from "@calcom/dayjs"; - -function isOutOfBounds( - time: dayjs.ConfigType, - { - periodType, - periodDays, - periodCountCalendarDays, - periodStartDate, - periodEndDate, - }: Pick< - EventType, - "periodType" | "periodDays" | "periodCountCalendarDays" | "periodStartDate" | "periodEndDate" - > -) { - const date = dayjs(time); - periodDays = periodDays || 0; - - switch (periodType) { - case PeriodType.ROLLING: { - const periodRollingEndDay = periodCountCalendarDays - ? dayjs().utcOffset(date.utcOffset()).add(periodDays, "days").endOf("day") - : dayjs().utcOffset(date.utcOffset()).businessDaysAdd(periodDays).endOf("day"); - return date.endOf("day").isAfter(periodRollingEndDay); - } - - case PeriodType.RANGE: { - const periodRangeStartDay = dayjs(periodStartDate).utcOffset(date.utcOffset()).endOf("day"); - const periodRangeEndDay = dayjs(periodEndDate).utcOffset(date.utcOffset()).endOf("day"); - return date.endOf("day").isBefore(periodRangeStartDay) || date.endOf("day").isAfter(periodRangeEndDay); - } - - case PeriodType.UNLIMITED: - default: - return false; - } -} - -export default isOutOfBounds; +/* Prefer import from `@calcom/lib/isOutOfBounds` */ +export * from "@calcom/lib/isOutOfBounds"; +export { default } from "@calcom/lib/isOutOfBounds"; diff --git a/apps/web/lib/parseDate.ts b/apps/web/lib/parseDate.ts index 1b07301e9c..4d068fe427 100644 --- a/apps/web/lib/parseDate.ts +++ b/apps/web/lib/parseDate.ts @@ -2,10 +2,10 @@ import { I18n } from "next-i18next"; import { RRule } from "rrule"; import dayjs, { Dayjs } from "@calcom/dayjs"; +import { inferQueryOutput } from "@calcom/trpc/react"; import { RecurringEvent } from "@calcom/types/Calendar"; import { detectBrowserTimeFormat } from "@lib/timeFormat"; -import { inferQueryOutput } from "@lib/trpc"; import { parseZone } from "./parseZone"; diff --git a/apps/web/lib/saml.ts b/apps/web/lib/saml.ts index 8dda87d125..6af24b61c9 100644 --- a/apps/web/lib/saml.ts +++ b/apps/web/lib/saml.ts @@ -1,8 +1,8 @@ import { PrismaClient } from "@prisma/client"; -import { BASE_URL } from "@lib/config/constants"; +import { TRPCError } from "@calcom/trpc/server"; -import { TRPCError } from "@trpc/server"; +import { BASE_URL } from "@lib/config/constants"; export const samlDatabaseUrl = process.env.SAML_DATABASE_URL || ""; export const samlLoginUrl = BASE_URL; diff --git a/apps/web/lib/slots.ts b/apps/web/lib/slots.ts index 1e48700249..82c1fff3e7 100644 --- a/apps/web/lib/slots.ts +++ b/apps/web/lib/slots.ts @@ -1,114 +1,3 @@ -import dayjs, { Dayjs } from "@calcom/dayjs"; - -import { getWorkingHours } from "./availability"; -import { WorkingHours } from "./types/schedule"; - -export type GetSlots = { - inviteeDate: Dayjs; - frequency: number; - workingHours: WorkingHours[]; - minimumBookingNotice: number; - eventLength: number; -}; -export type WorkingHoursTimeFrame = { startTime: number; endTime: number }; - -const splitAvailableTime = ( - startTimeMinutes: number, - endTimeMinutes: number, - frequency: number, - eventLength: number -): Array => { - let initialTime = startTimeMinutes; - const finalizationTime = endTimeMinutes; - const result = [] as Array; - while (initialTime < finalizationTime) { - const periodTime = initialTime + frequency; - const slotEndTime = initialTime + eventLength; - /* - check if the slot end time surpasses availability end time of the user - 1 minute is added to round up the hour mark so that end of the slot is considered in the check instead of x9 - eg: if finalization time is 11:59, slotEndTime is 12:00, we ideally want the slot to be available - */ - if (slotEndTime <= finalizationTime + 1) result.push({ startTime: initialTime, endTime: periodTime }); - initialTime += frequency; - } - return result; -}; - -const getSlots = ({ inviteeDate, frequency, minimumBookingNotice, workingHours, eventLength }: GetSlots) => { - // current date in invitee tz - const startDate = dayjs().add(minimumBookingNotice, "minute"); - const startOfDay = dayjs.utc().startOf("day"); - const startOfInviteeDay = inviteeDate.startOf("day"); - // checks if the start date is in the past - - /** - * TODO: change "day" for "hour" to stop displaying 1 day before today - * This is displaying a day as available as sometimes difference between two dates is < 24 hrs. - * But when doing timezones an available day for an owner can be 2 days available in other users tz. - * - * */ - if (inviteeDate.isBefore(startDate, "day")) { - return []; - } - - const localWorkingHours = getWorkingHours( - { utcOffset: -inviteeDate.utcOffset() }, - workingHours.map((schedule) => ({ - days: schedule.days, - startTime: startOfDay.add(schedule.startTime, "minute"), - endTime: startOfDay.add(schedule.endTime, "minute"), - })) - ).filter((hours) => hours.days.includes(inviteeDate.day())); - - const slots: Dayjs[] = []; - - const slotsTimeFrameAvailable = [] as Array; - // Here we split working hour in chunks for every frequency available that can fit in whole working hours - const computedLocalWorkingHours: WorkingHoursTimeFrame[] = []; - let tempComputeTimeFrame: WorkingHoursTimeFrame | undefined; - const computeLength = localWorkingHours.length - 1; - const makeTimeFrame = (item: typeof localWorkingHours[0]): WorkingHoursTimeFrame => ({ - startTime: item.startTime, - endTime: item.endTime, - }); - localWorkingHours.forEach((item, index) => { - if (!tempComputeTimeFrame) { - tempComputeTimeFrame = makeTimeFrame(item); - } else { - // please check the comment in splitAvailableTime func for the added 1 minute - if (tempComputeTimeFrame.endTime + 1 === item.startTime) { - // to deal with time that across the day, e.g. from 11:59 to to 12:01 - tempComputeTimeFrame.endTime = item.endTime; - } else { - computedLocalWorkingHours.push(tempComputeTimeFrame); - tempComputeTimeFrame = makeTimeFrame(item); - } - } - if (index == computeLength) { - computedLocalWorkingHours.push(tempComputeTimeFrame); - } - }); - computedLocalWorkingHours.forEach((item) => { - slotsTimeFrameAvailable.push(...splitAvailableTime(item.startTime, item.endTime, frequency, eventLength)); - }); - - slotsTimeFrameAvailable.forEach((item) => { - const slot = startOfInviteeDay.add(item.startTime, "minute"); - // Validating slot its not on the past - if (!slot.isBefore(startDate)) { - slots.push(slot); - } - }); - - const uniq = (a: Dayjs[]) => { - const seen: Record = {}; - return a.filter((item) => { - return seen.hasOwnProperty(item.format()) ? false : (seen[item.format()] = true); - }); - }; - - return uniq(slots); -}; - -export default getSlots; +/** Prefer import from `@calcom/lib/slots` */ +export * from "@calcom/lib/slots"; +export { default } from "@calcom/lib/slots"; diff --git a/apps/web/next-i18next.config.js b/apps/web/next-i18next.config.js index 923695bde3..0d55e2dabb 100644 --- a/apps/web/next-i18next.config.js +++ b/apps/web/next-i18next.config.js @@ -1,36 +1,10 @@ const path = require("path"); +const i18nConfig = require("@calcom/config/next-i18next.config"); /** @type {import("next-i18next").UserConfig} */ const config = { - i18n: { - defaultLocale: "en", - locales: [ - "en", - "fr", - "it", - "ru", - "es", - "de", - "pt", - "ro", - "nl", - "pt-BR", - "es-419", - "ko", - "ja", - "pl", - "ar", - "iw", - "zh-CN", - "zh-TW", - "cs", - "sr", - "sv", - "vi", - ], - }, + ...i18nConfig, localePath: path.resolve("./public/static/locales"), - reloadOnPrerender: process.env.NODE_ENV !== "production", }; module.exports = config; diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 9d16c1fc8b..62aa8d0781 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -5,14 +5,15 @@ const withTM = require("next-transpile-modules")([ "@calcom/core", "@calcom/dayjs", "@calcom/ee", - "@calcom/lib", - "@calcom/prisma", - "@calcom/stripe", - "@calcom/ui", "@calcom/emails", "@calcom/embed-core", "@calcom/embed-react", "@calcom/embed-snippet", + "@calcom/lib", + "@calcom/prisma", + "@calcom/stripe", + "@calcom/trpc", + "@calcom/ui", ]); const { i18n } = require("./next-i18next.config"); diff --git a/apps/web/package.json b/apps/web/package.json index 5721dc1988..b84bb6d488 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -28,8 +28,8 @@ }, "dependencies": { "@boxyhq/saml-jackson": "0.3.6", - "@calcom/app-store": "*", "@calcom/app-store-cli": "*", + "@calcom/app-store": "*", "@calcom/core": "*", "@calcom/dayjs": "*", "@calcom/ee": "*", @@ -39,6 +39,7 @@ "@calcom/lib": "*", "@calcom/prisma": "*", "@calcom/stripe": "*", + "@calcom/trpc": "*", "@calcom/tsconfig": "*", "@calcom/ui": "*", "@daily-co/daily-js": "^0.26.0", @@ -61,10 +62,6 @@ "@radix-ui/react-tooltip": "^0.1.0", "@stripe/react-stripe-js": "^1.8.0", "@stripe/stripe-js": "^1.29.0", - "@trpc/client": "^9.25.2", - "@trpc/next": "^9.25.2", - "@trpc/react": "^9.25.2", - "@trpc/server": "^9.25.2", "@vercel/edge-functions-ui": "^0.2.1", "@wojtekmaj/react-daterange-picker": "^3.3.1", "accept-language-parser": "^1.5.0", diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index 57db0b2baa..55126806d4 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -4,6 +4,14 @@ import Head from "next/head"; import superjson from "superjson"; import "@calcom/embed-core/src/embed-iframe"; +import { httpBatchLink } from "@calcom/trpc/client/links/httpBatchLink"; +import { httpLink } from "@calcom/trpc/client/links/httpLink"; +import { loggerLink } from "@calcom/trpc/client/links/loggerLink"; +import { splitLink } from "@calcom/trpc/client/links/splitLink"; +import { withTRPC } from "@calcom/trpc/next"; +import type { TRPCClientErrorLike } from "@calcom/trpc/react"; +import { Maybe } from "@calcom/trpc/server"; +import type { AppRouter } from "@calcom/trpc/server/routers/_app"; import LicenseRequired from "@ee/components/LicenseRequired"; import AppProviders, { AppProps } from "@lib/app-providers"; @@ -12,15 +20,6 @@ import useTheme from "@lib/hooks/useTheme"; import I18nLanguageHandler from "@components/I18nLanguageHandler"; -import type { AppRouter } from "@server/routers/_app"; -import { httpBatchLink } from "@trpc/client/links/httpBatchLink"; -import { httpLink } from "@trpc/client/links/httpLink"; -import { loggerLink } from "@trpc/client/links/loggerLink"; -import { splitLink } from "@trpc/client/links/splitLink"; -import { withTRPC } from "@trpc/next"; -import type { TRPCClientErrorLike } from "@trpc/react"; -import { Maybe } from "@trpc/server"; - import { ContractsProvider } from "../contexts/contractsContext"; import "../styles/fonts.css"; import "../styles/globals.css"; diff --git a/apps/web/pages/api/availability/eventtype.ts b/apps/web/pages/api/availability/eventtype.ts index be214855d5..e5721a5258 100644 --- a/apps/web/pages/api/availability/eventtype.ts +++ b/apps/web/pages/api/availability/eventtype.ts @@ -1,9 +1,9 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import { getSession } from "@lib/auth"; +import { createContext } from "@calcom/trpc/server/createContext"; +import { viewerRouter } from "@calcom/trpc/server/routers/viewer"; -import { createContext } from "@server/createContext"; -import { viewerRouter } from "@server/routers/viewer"; +import { getSession } from "@lib/auth"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const session = await getSession({ req }); diff --git a/apps/web/pages/api/book/confirm.ts b/apps/web/pages/api/book/confirm.ts index 76b0dd0529..77fd3ff925 100644 --- a/apps/web/pages/api/book/confirm.ts +++ b/apps/web/pages/api/book/confirm.ts @@ -8,8 +8,8 @@ import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib"; import logger from "@calcom/lib/logger"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; +import { refund } from "@calcom/stripe/server"; import type { AdditionalInformation, CalendarEvent } from "@calcom/types/Calendar"; -import { refund } from "@ee/lib/stripe/server"; import { scheduleWorkflowReminders } from "@ee/lib/workflows/reminders/reminderScheduler"; import { getSession } from "@lib/auth"; diff --git a/apps/web/pages/api/book/event.ts b/apps/web/pages/api/book/event.ts index 76ba1a5bde..2ea3373d59 100644 --- a/apps/web/pages/api/book/event.ts +++ b/apps/web/pages/api/book/event.ts @@ -18,20 +18,20 @@ import { import { getLuckyUsers, isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib"; import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents"; import { getErrorFromUnknown } from "@calcom/lib/errors"; +import isOutOfBounds from "@calcom/lib/isOutOfBounds"; import logger from "@calcom/lib/logger"; import { defaultResponder } from "@calcom/lib/server"; import prisma, { userSelect } from "@calcom/prisma"; import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils"; +import { handlePayment } from "@calcom/stripe/server"; import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime"; import type { AdditionalInformation, CalendarEvent } from "@calcom/types/Calendar"; import type { EventResult, PartialReference } from "@calcom/types/EventManager"; -import { handlePayment } from "@ee/lib/stripe/server"; import { scheduleWorkflowReminders } from "@ee/lib/workflows/reminders/reminderScheduler"; import { HttpError } from "@lib/core/http/error"; import { ensureArray } from "@lib/ensureArray"; import { getEventName } from "@lib/event"; -import isOutOfBounds from "@lib/isOutOfBounds"; import sendPayload from "@lib/webhooks/sendPayload"; import getSubscribers from "@lib/webhooks/subscriptions"; diff --git a/apps/web/pages/api/cancel.ts b/apps/web/pages/api/cancel.ts index 582d2d5f8e..1ab17eff59 100644 --- a/apps/web/pages/api/cancel.ts +++ b/apps/web/pages/api/cancel.ts @@ -19,8 +19,8 @@ import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib"; import { HttpError } from "@calcom/lib/http-error"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import prisma, { bookingMinimalSelect } from "@calcom/prisma"; +import { refund } from "@calcom/stripe/server"; import type { CalendarEvent } from "@calcom/types/Calendar"; -import { refund } from "@ee/lib/stripe/server"; import { deleteScheduledEmailReminder } from "@ee/lib/workflows/reminders/emailReminderManager"; import { sendCancelledReminders } from "@ee/lib/workflows/reminders/reminderScheduler"; import { deleteScheduledSMSReminder } from "@ee/lib/workflows/reminders/smsReminderManager"; diff --git a/apps/web/pages/api/intent-username/index.ts b/apps/web/pages/api/intent-username/index.ts index d43cbf874f..c74002830b 100644 --- a/apps/web/pages/api/intent-username/index.ts +++ b/apps/web/pages/api/intent-username/index.ts @@ -2,11 +2,10 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { getSession } from "next-auth/react"; import { defaultHandler } from "@calcom/lib/server"; +import { checkUsername } from "@calcom/lib/server/checkUsername"; import prisma from "@calcom/prisma"; import { userMetadata as zodUserMetadata } from "@calcom/prisma/zod-utils"; -import { checkUsername } from "@lib/core/server/checkUsername"; - export async function getHandler(req: NextApiRequest, res: NextApiResponse) { const { intentUsername } = req.body; // Check that user is authenticated diff --git a/apps/web/pages/api/teams/[team]/index.ts b/apps/web/pages/api/teams/[team]/index.ts index 881540b28a..e576069c13 100644 --- a/apps/web/pages/api/teams/[team]/index.ts +++ b/apps/web/pages/api/teams/[team]/index.ts @@ -1,8 +1,9 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { getTeamWithMembers } from "@calcom/lib/server/queries/teams"; + import { getSession } from "@lib/auth"; import prisma from "@lib/prisma"; -import { getTeamWithMembers } from "@lib/queries/teams"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const session = await getSession({ req: req }); diff --git a/apps/web/pages/api/trpc/[trpc].ts b/apps/web/pages/api/trpc/[trpc].ts index da0ab1feda..7204fc2a30 100644 --- a/apps/web/pages/api/trpc/[trpc].ts +++ b/apps/web/pages/api/trpc/[trpc].ts @@ -1,9 +1,9 @@ /** * This file contains tRPC's HTTP response handler */ -import { createContext } from "@server/createContext"; -import { appRouter } from "@server/routers/_app"; -import * as trpcNext from "@trpc/server/adapters/next"; +import * as trpcNext from "@calcom/trpc/server/adapters/next"; +import { createContext } from "@calcom/trpc/server/createContext"; +import { appRouter } from "@calcom/trpc/server/routers/_app"; export default trpcNext.createNextApiHandler({ router: appRouter, diff --git a/apps/web/pages/api/username.ts b/apps/web/pages/api/username.ts index 57fddb64d0..9251aada56 100644 --- a/apps/web/pages/api/username.ts +++ b/apps/web/pages/api/username.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import { checkUsername } from "@lib/core/server/checkUsername"; +import { checkUsername } from "@calcom/lib/server/checkUsername"; type Response = { available: boolean; diff --git a/apps/web/pages/apps/installed.tsx b/apps/web/pages/apps/installed.tsx index f0b46d02cc..fc39738c71 100644 --- a/apps/web/pages/apps/installed.tsx +++ b/apps/web/pages/apps/installed.tsx @@ -6,6 +6,7 @@ import { InstallAppButton } from "@calcom/app-store/components"; import { WEBSITE_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import type { App } from "@calcom/types/App"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; @@ -14,7 +15,6 @@ import EmptyScreen from "@calcom/ui/EmptyScreen"; import { QueryCell } from "@lib/QueryCell"; import classNames from "@lib/classNames"; import { HttpError } from "@lib/core/http/error"; -import { trpc } from "@lib/trpc"; import AppsShell from "@components/AppsShell"; import { List, ListItem, ListItemText, ListItemTitle } from "@components/List"; diff --git a/apps/web/pages/auth/sso/[provider].tsx b/apps/web/pages/auth/sso/[provider].tsx index 9b0fc6fd12..707e640ec0 100644 --- a/apps/web/pages/auth/sso/[provider].tsx +++ b/apps/web/pages/auth/sso/[provider].tsx @@ -3,12 +3,12 @@ import { signIn } from "next-auth/react"; import { useRouter } from "next/router"; import { useEffect } from "react"; +import { checkUsername } from "@calcom/lib/server/checkUsername"; import stripe from "@calcom/stripe/server"; import { getPremiumPlanPrice } from "@calcom/stripe/utils"; import { asStringOrNull } from "@lib/asStringOrNull"; import { getSession } from "@lib/auth"; -import { checkUsername } from "@lib/core/server/checkUsername"; import prisma from "@lib/prisma"; import { hostedCal, isSAMLLoginEnabled, samlProductID, samlTenantID, samlTenantProduct } from "@lib/saml"; import { inferSSRProps } from "@lib/types/inferSSRProps"; diff --git a/apps/web/pages/availability/[schedule].tsx b/apps/web/pages/availability/[schedule].tsx index 224798a858..94774d8321 100644 --- a/apps/web/pages/availability/[schedule].tsx +++ b/apps/web/pages/availability/[schedule].tsx @@ -6,13 +6,13 @@ import { Controller, useForm } from "react-hook-form"; import { DEFAULT_SCHEDULE, availabilityAsString } from "@calcom/lib/availability"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import Switch from "@calcom/ui/Switch"; import { Form } from "@calcom/ui/form/fields"; import { QueryCell } from "@lib/QueryCell"; import { HttpError } from "@lib/core/http/error"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import Shell from "@components/Shell"; import Schedule from "@components/availability/Schedule"; diff --git a/apps/web/pages/availability/index.tsx b/apps/web/pages/availability/index.tsx index 3653344840..8181ed674e 100644 --- a/apps/web/pages/availability/index.tsx +++ b/apps/web/pages/availability/index.tsx @@ -2,11 +2,11 @@ import { ClockIcon } from "@heroicons/react/outline"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import EmptyScreen from "@calcom/ui/EmptyScreen"; import { withQuery } from "@lib/QueryCell"; import { HttpError } from "@lib/core/http/error"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import Shell from "@components/Shell"; import { NewScheduleButton } from "@components/availability/NewScheduleButton"; diff --git a/apps/web/pages/availability/troubleshoot.tsx b/apps/web/pages/availability/troubleshoot.tsx index eafa6195cb..0d0de59433 100644 --- a/apps/web/pages/availability/troubleshoot.tsx +++ b/apps/web/pages/availability/troubleshoot.tsx @@ -2,9 +2,9 @@ import { useEffect, useState } from "react"; import dayjs, { Dayjs } from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { QueryCell } from "@lib/QueryCell"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import Loader from "@components/Loader"; import Shell from "@components/Shell"; diff --git a/apps/web/pages/bookings/[status].tsx b/apps/web/pages/bookings/[status].tsx index 944fa9be14..418f1fc107 100644 --- a/apps/web/pages/bookings/[status].tsx +++ b/apps/web/pages/bookings/[status].tsx @@ -4,12 +4,12 @@ import { Fragment } from "react"; import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { inferQueryInput, inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import EmptyScreen from "@calcom/ui/EmptyScreen"; import { useInViewObserver } from "@lib/hooks/useInViewObserver"; -import { inferQueryInput, inferQueryOutput, trpc } from "@lib/trpc"; import BookingsShell from "@components/BookingsShell"; import Shell from "@components/Shell"; @@ -76,7 +76,7 @@ export default function Bookings() { }; return ( }> - +
diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx index c960e094b3..2bac1df15e 100644 --- a/apps/web/pages/event-types/[type].tsx +++ b/apps/web/pages/event-types/[type].tsx @@ -37,6 +37,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import prisma from "@calcom/prisma"; import { StripeData } from "@calcom/stripe/server"; +import { trpc } from "@calcom/trpc/react"; import { RecurringEvent } from "@calcom/types/Calendar"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; @@ -52,7 +53,6 @@ import { HttpError } from "@lib/core/http/error"; import { isSuccessRedirectAvailable } from "@lib/isSuccessRedirectAvailable"; import { LocationObject, LocationType } from "@lib/location"; import { slugify } from "@lib/slugify"; -import { trpc } from "@lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; import { ClientSuspense } from "@components/ClientSuspense"; diff --git a/apps/web/pages/event-types/index.tsx b/apps/web/pages/event-types/index.tsx index 2e28209fab..b7042c7de8 100644 --- a/apps/web/pages/event-types/index.tsx +++ b/apps/web/pages/event-types/index.tsx @@ -22,6 +22,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 { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Alert } from "@calcom/ui/Alert"; import { Dialog } from "@calcom/ui/Dialog"; @@ -37,7 +38,6 @@ import { Tooltip } from "@calcom/ui/Tooltip"; import { withQuery } from "@lib/QueryCell"; import classNames from "@lib/classNames"; import { HttpError } from "@lib/core/http/error"; -import { inferQueryOutput, trpc } from "@lib/trpc"; import { EmbedButton, EmbedDialog } from "@components/Embed"; import Shell from "@components/Shell"; diff --git a/apps/web/pages/getting-started.tsx b/apps/web/pages/getting-started.tsx index e8a9682347..06947fb8e9 100644 --- a/apps/web/pages/getting-started.tsx +++ b/apps/web/pages/getting-started.tsx @@ -17,6 +17,7 @@ import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/Cale import dayjs from "@calcom/dayjs"; import { DOCS_URL } from "@calcom/lib/constants"; import { fetchUsername } from "@calcom/lib/fetchUsername"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import { Form } from "@calcom/ui/form/fields"; @@ -26,7 +27,6 @@ import { DEFAULT_SCHEDULE } from "@lib/availability"; import { useLocale } from "@lib/hooks/useLocale"; import prisma from "@lib/prisma"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; -import { trpc } from "@lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; import { Schedule as ScheduleType } from "@lib/types/schedule"; diff --git a/apps/web/pages/settings/developer.tsx b/apps/web/pages/settings/developer.tsx index 2c052e6bee..2b639a4934 100644 --- a/apps/web/pages/settings/developer.tsx +++ b/apps/web/pages/settings/developer.tsx @@ -1,8 +1,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import ApiKeyListContainer from "@ee/components/apiKeys/ApiKeyListContainer"; -import { trpc } from "@lib/trpc"; - import SettingsShell from "@components/SettingsShell"; import WebhookListContainer from "@components/webhook/WebhookListContainer"; diff --git a/apps/web/pages/settings/profile.tsx b/apps/web/pages/settings/profile.tsx index a571b0652d..995f914864 100644 --- a/apps/web/pages/settings/profile.tsx +++ b/apps/web/pages/settings/profile.tsx @@ -8,6 +8,9 @@ import TimezoneSelect, { ITimezone } from "react-timezone-select"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { TRPCClientErrorLike } from "@calcom/trpc/client"; +import { trpc } from "@calcom/trpc/react"; +import { AppRouter } from "@calcom/trpc/server/routers/_app"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; @@ -18,7 +21,6 @@ import { getSession } from "@lib/auth"; import { nameOfDay } from "@lib/core/i18n/weekday"; import { isBrandingHidden } from "@lib/isBrandingHidden"; import prisma from "@lib/prisma"; -import { trpc } from "@lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; import ImageUploader from "@components/ImageUploader"; @@ -31,9 +33,6 @@ import { UsernameAvailability } from "@components/ui/UsernameAvailability"; import ColorPicker from "@components/ui/colorpicker"; import Select from "@components/ui/form/Select"; -import { AppRouter } from "@server/routers/_app"; -import { TRPCClientErrorLike } from "@trpc/client"; - import { UpgradeToProDialog } from "../../components/UpgradeToProDialog"; type Props = inferSSRProps; diff --git a/apps/web/pages/settings/security.tsx b/apps/web/pages/settings/security.tsx index b7493a8f4d..bb2f0eab04 100644 --- a/apps/web/pages/settings/security.tsx +++ b/apps/web/pages/settings/security.tsx @@ -2,10 +2,10 @@ import { IdentityProvider } from "@prisma/client"; import React from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import SAMLConfiguration from "@ee/components/saml/Configuration"; import { identityProviderNameMap } from "@lib/auth"; -import { trpc } from "@lib/trpc"; import SettingsShell from "@components/SettingsShell"; import ChangePasswordSection from "@components/security/ChangePasswordSection"; diff --git a/apps/web/pages/settings/teams/[id]/index.tsx b/apps/web/pages/settings/teams/[id]/index.tsx index 7032bd7568..2d12a1a7c7 100644 --- a/apps/web/pages/settings/teams/[id]/index.tsx +++ b/apps/web/pages/settings/teams/[id]/index.tsx @@ -4,6 +4,7 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { SkeletonAvatar, SkeletonText } from "@calcom/ui"; import { Alert } from "@calcom/ui/Alert"; import { Button } from "@calcom/ui/Button"; @@ -13,7 +14,6 @@ import { QueryCell } from "@lib/QueryCell"; import { getPlaceholderAvatar } from "@lib/getPlaceholderAvatar"; import useCurrentUserId from "@lib/hooks/useCurrentUserId"; import { useLocale } from "@lib/hooks/useLocale"; -import { trpc } from "@lib/trpc"; import Shell from "@components/Shell"; import DisableTeamImpersonation from "@components/team/DisableTeamImpersonation"; diff --git a/apps/web/pages/settings/teams/index.tsx b/apps/web/pages/settings/teams/index.tsx index 04f4e526be..e110def713 100644 --- a/apps/web/pages/settings/teams/index.tsx +++ b/apps/web/pages/settings/teams/index.tsx @@ -5,12 +5,12 @@ import { Trans } from "next-i18next"; import { useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import Button from "@calcom/ui/Button"; import EmptyScreen from "@calcom/ui/EmptyScreen"; import useMeQuery from "@lib/hooks/useMeQuery"; -import { trpc } from "@lib/trpc"; import SettingsShell from "@components/SettingsShell"; import SkeletonLoaderTeamList from "@components/team/SkeletonloaderTeamList"; diff --git a/apps/web/pages/team/[slug].tsx b/apps/web/pages/team/[slug].tsx index d90d07f595..3510dbcce8 100644 --- a/apps/web/pages/team/[slug].tsx +++ b/apps/web/pages/team/[slug].tsx @@ -8,6 +8,7 @@ import React, { useEffect } from "react"; import { useIsEmbed } from "@calcom/embed-core/embed-iframe"; import { CAL_URL } from "@calcom/lib/constants"; +import { getTeamWithMembers } from "@calcom/lib/server/queries/teams"; import Button from "@calcom/ui/Button"; import { getPlaceholderAvatar } from "@lib/getPlaceholderAvatar"; @@ -15,7 +16,6 @@ import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally"; import { useLocale } from "@lib/hooks/useLocale"; import useTheme from "@lib/hooks/useTheme"; import { useToggleQuery } from "@lib/hooks/useToggleQuery"; -import { getTeamWithMembers } from "@lib/queries/teams"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; import { inferSSRProps } from "@lib/types/inferSSRProps"; diff --git a/apps/web/server/lib/i18n.ts b/apps/web/server/lib/i18n.ts index 19528ab7d0..0a3f56aead 100644 --- a/apps/web/server/lib/i18n.ts +++ b/apps/web/server/lib/i18n.ts @@ -1,18 +1 @@ -import i18next from "i18next"; -import { i18n as nexti18next } from "next-i18next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; - -export const getTranslation = async (locale: string, ns: string) => { - const create = async () => { - const { _nextI18Next } = await serverSideTranslations(locale, [ns]); - const _i18n = i18next.createInstance(); - _i18n.init({ - lng: locale, - resources: _nextI18Next.initialI18nStore, - fallbackLng: _nextI18Next.userConfig?.i18n.defaultLocale, - }); - return _i18n; - }; - const _i18n = nexti18next != null ? nexti18next : await create(); - return _i18n.getFixedT(locale, ns); -}; +export * from "@calcom/lib/server/i18n"; diff --git a/apps/web/server/lib/ssg.ts b/apps/web/server/lib/ssg.ts index a7abd8668d..090adbc3c1 100644 --- a/apps/web/server/lib/ssg.ts +++ b/apps/web/server/lib/ssg.ts @@ -3,10 +3,9 @@ import { i18n } from "next-i18next.config"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import superjson from "superjson"; -import prisma from "@lib/prisma"; - -import { appRouter } from "@server/routers/_app"; -import { createSSGHelpers } from "@trpc/react/ssg"; +import prisma from "@calcom/prisma"; +import { createSSGHelpers } from "@calcom/trpc/react/ssg"; +import { appRouter } from "@calcom/trpc/server/routers/_app"; /** * Initialize static site rendering tRPC helpers. diff --git a/apps/web/server/lib/ssr.ts b/apps/web/server/lib/ssr.ts index c57a0a5111..80b8108da8 100644 --- a/apps/web/server/lib/ssr.ts +++ b/apps/web/server/lib/ssr.ts @@ -1,10 +1,9 @@ import { GetServerSidePropsContext } from "next"; import superjson from "superjson"; -import { createContext } from "@server/createContext"; -import { createSSGHelpers } from "@trpc/react/ssg"; - -import { appRouter } from "../routers/_app"; +import { createSSGHelpers } from "@calcom/trpc/react/ssg"; +import { createContext } from "@calcom/trpc/server/createContext"; +import { appRouter } from "@calcom/trpc/server/routers/_app"; /** * Initialize server-side rendering tRPC helpers. diff --git a/apps/web/test/lib/getSchedule.test.ts b/apps/web/test/lib/getSchedule.test.ts index bf1d590f69..15b92e7007 100644 --- a/apps/web/test/lib/getSchedule.test.ts +++ b/apps/web/test/lib/getSchedule.test.ts @@ -5,8 +5,7 @@ import { v4 as uuidv4 } from "uuid"; import logger from "@calcom/lib/logger"; import prisma from "@calcom/prisma"; import { BookingStatus, PeriodType } from "@calcom/prisma/client"; - -import { getSchedule } from "../../server/routers/viewer/slots"; +import { getSchedule } from "@calcom/trpc/server/routers/viewer/slots"; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace diff --git a/apps/web/test/lib/slots.test.ts b/apps/web/test/lib/slots.test.ts index 38285b7ba9..c08324953f 100644 --- a/apps/web/test/lib/slots.test.ts +++ b/apps/web/test/lib/slots.test.ts @@ -2,10 +2,10 @@ import { expect, it } from "@jest/globals"; import MockDate from "mockdate"; import dayjs from "@calcom/dayjs"; +import getSlots from "@calcom/lib/slots"; import { MINUTES_DAY_END, MINUTES_DAY_START } from "@lib/availability"; import { getFilteredTimes } from "@lib/hooks/useSlots"; -import getSlots from "@lib/slots"; MockDate.set("2021-06-20T11:59:59Z"); diff --git a/package.json b/package.json index 3b2dc17ce1..8534db7b12 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ ], "scripts": { "build": "turbo run build --scope=\"@calcom/web\" --include-dependencies", - "clean": "turbo run clean && rm -rf node_modules", + "clean": "find . -name node_modules -o -name .next -o -name .turbo -o -name dist -type d -prune | xargs rm -rf", "db-deploy": "turbo run db-deploy", "db-seed": "turbo run db-seed", "db-studio": "yarn workspace @calcom/prisma db-studio", diff --git a/packages/app-store/components.tsx b/packages/app-store/components.tsx index f9b7099a5e..18556f9af9 100644 --- a/packages/app-store/components.tsx +++ b/packages/app-store/components.tsx @@ -4,10 +4,9 @@ import { useState, useEffect, useRef } from "react"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; import type { App } from "@calcom/types/App"; -import { trpc } from "@lib/trpc"; - import { UpgradeToProDialog } from "@components/UpgradeToProDialog"; import { InstallAppButtonMap } from "./apps.browser.generated"; diff --git a/packages/app-store/ee/routing_forms/components/SideBar.tsx b/packages/app-store/ee/routing_forms/components/SideBar.tsx index c5520157c1..f0a7f0cd4c 100644 --- a/packages/app-store/ee/routing_forms/components/SideBar.tsx +++ b/packages/app-store/ee/routing_forms/components/SideBar.tsx @@ -4,9 +4,9 @@ import { useRouter } from "next/router"; import { CAL_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Switch } from "@calcom/ui"; import { DialogTrigger, Dialog } from "@calcom/ui/Dialog"; -import { trpc } from "@calcom/web/lib/trpc"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; diff --git a/packages/app-store/ee/routing_forms/pages/form-edit/[...appPages].tsx b/packages/app-store/ee/routing_forms/pages/form-edit/[...appPages].tsx index 57de747685..0235fecd8e 100644 --- a/packages/app-store/ee/routing_forms/pages/form-edit/[...appPages].tsx +++ b/packages/app-store/ee/routing_forms/pages/form-edit/[...appPages].tsx @@ -1,16 +1,16 @@ -import { TrashIcon, PlusIcon, ArrowUpIcon, CollectionIcon, ArrowDownIcon } from "@heroicons/react/solid"; +import { ArrowDownIcon, ArrowUpIcon, CollectionIcon, PlusIcon, TrashIcon } from "@heroicons/react/solid"; import { useRouter } from "next/router"; -import { useState, useEffect } from "react"; -import { useForm, UseFormReturn, useFieldArray, Controller } from "react-hook-form"; +import { useEffect, useState } from "react"; +import { Controller, useFieldArray, useForm, UseFormReturn } from "react-hook-form"; import { v4 as uuidv4 } from "uuid"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps"; -import { Button, Select, BooleanToggleGroup, EmptyScreen } from "@calcom/ui"; +import { BooleanToggleGroup, Button, EmptyScreen, Select } from "@calcom/ui"; import { Form, TextArea } from "@calcom/ui/form/fields"; -import { trpc } from "@calcom/web/lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; diff --git a/packages/app-store/ee/routing_forms/pages/forms/[...appPages].tsx b/packages/app-store/ee/routing_forms/pages/forms/[...appPages].tsx index bd42135388..0ebda3d0d1 100644 --- a/packages/app-store/ee/routing_forms/pages/forms/[...appPages].tsx +++ b/packages/app-store/ee/routing_forms/pages/forms/[...appPages].tsx @@ -17,6 +17,7 @@ import classNames from "@calcom/lib/classNames"; import { CAL_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps"; import { Button, EmptyScreen, Tooltip } from "@calcom/ui"; import Dropdown, { @@ -25,7 +26,6 @@ import Dropdown, { DropdownMenuSeparator, DropdownMenuTrigger, } from "@calcom/ui/Dropdown"; -import { trpc } from "@calcom/web/lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; diff --git a/packages/app-store/ee/routing_forms/pages/route-builder/[...appPages].tsx b/packages/app-store/ee/routing_forms/pages/route-builder/[...appPages].tsx index 08e1a28967..98786bec50 100644 --- a/packages/app-store/ee/routing_forms/pages/route-builder/[...appPages].tsx +++ b/packages/app-store/ee/routing_forms/pages/route-builder/[...appPages].tsx @@ -7,11 +7,11 @@ import { JsonTree, ImmutableTree, BuilderProps } from "react-awesome-query-build import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps"; import { inferSSRProps } from "@calcom/types/inferSSRProps"; import { Button } from "@calcom/ui"; import { Label } from "@calcom/ui/form/fields"; -import { trpc } from "@calcom/web/lib/trpc"; import PencilEdit from "@components/PencilEdit"; import { SelectWithValidation as Select } from "@components/ui/form/Select"; diff --git a/packages/app-store/ee/routing_forms/pages/routing-link/[...appPages].tsx b/packages/app-store/ee/routing_forms/pages/routing-link/[...appPages].tsx index f207dfed6f..0d4e5883a7 100644 --- a/packages/app-store/ee/routing_forms/pages/routing-link/[...appPages].tsx +++ b/packages/app-store/ee/routing_forms/pages/routing-link/[...appPages].tsx @@ -7,10 +7,10 @@ import { Toaster } from "react-hot-toast"; import { v4 as uuidv4 } from "uuid"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { AppGetServerSidePropsContext, AppPrisma } from "@calcom/types/AppGetServerSideProps"; import { inferSSRProps } from "@calcom/types/inferSSRProps"; import { Button } from "@calcom/ui"; -import { trpc } from "@calcom/web/lib/trpc"; import { getSerializableForm } from "../../utils"; import { getQueryBuilderConfig } from "../route-builder/[...appPages]"; diff --git a/packages/app-store/ee/routing_forms/trpc-router.ts b/packages/app-store/ee/routing_forms/trpc-router.ts index f079b284b5..c736eec0d7 100644 --- a/packages/app-store/ee/routing_forms/trpc-router.ts +++ b/packages/app-store/ee/routing_forms/trpc-router.ts @@ -2,12 +2,12 @@ import { Prisma, WebhookTriggerEvents } from "@prisma/client"; import { v4 as uuidv4 } from "uuid"; import { z } from "zod"; +import { TRPCError } from "@calcom/trpc/server"; +import { createProtectedRouter, createRouter } from "@calcom/trpc/server/createRouter"; + import { sendGenericWebhookPayload } from "@lib/webhooks/sendPayload"; import getWebhooks from "@lib/webhooks/subscriptions"; -import { createProtectedRouter, createRouter } from "@server/createRouter"; -import { TRPCError } from "@trpc/server"; - import { zodFields, zodRoutes } from "./zod"; const app_RoutingForms = createRouter() diff --git a/packages/app-store/wipemycalother/components/confirmDialog.tsx b/packages/app-store/wipemycalother/components/confirmDialog.tsx index a79f38a328..22e77cf939 100644 --- a/packages/app-store/wipemycalother/components/confirmDialog.tsx +++ b/packages/app-store/wipemycalother/components/confirmDialog.tsx @@ -1,19 +1,18 @@ -import { ClockIcon, XIcon } from "@heroicons/react/outline"; -import { Dispatch, SetStateAction } from "react"; -import { useState } from "react"; +import { ClockIcon } from "@heroicons/react/outline"; +import { Dispatch, SetStateAction, useState } from "react"; import { useMutation } from "react-query"; import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import logger from "@calcom/lib/logger"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; -import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog"; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog"; interface IConfirmDialogWipe { isOpenDialog: boolean; setIsOpenDialog: Dispatch>; - trpc: any; } interface IWipeMyCalAction { @@ -45,7 +44,7 @@ const wipeMyCalAction = async (props: IWipeMyCalAction) => { export const ConfirmDialog = (props: IConfirmDialogWipe) => { const { t } = useLocale(); - const { isOpenDialog, setIsOpenDialog, trpc } = props; + const { isOpenDialog, setIsOpenDialog } = props; const [isLoading, setIsLoading] = useState(false); const today = dayjs(); const initialDate = today.startOf("day"); diff --git a/packages/app-store/wipemycalother/components/wipeMyCalActionButton.tsx b/packages/app-store/wipemycalother/components/wipeMyCalActionButton.tsx index 476c868553..ad243f4051 100644 --- a/packages/app-store/wipemycalother/components/wipeMyCalActionButton.tsx +++ b/packages/app-store/wipemycalother/components/wipeMyCalActionButton.tsx @@ -1,17 +1,17 @@ import { useState } from "react"; +import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { ConfirmDialog } from "./confirmDialog"; interface IWipeMyCalActionButtonProps { - trpc: any; bookingsEmpty: boolean; bookingStatus: "upcoming" | "recurring" | "past" | "cancelled"; } const WipeMyCalActionButton = (props: IWipeMyCalActionButtonProps) => { - const { trpc, bookingsEmpty, bookingStatus } = props; + const { bookingsEmpty, bookingStatus } = props; const [openDialog, setOpenDialog] = useState(false); const { isSuccess, isLoading, data } = trpc.useQuery([ "viewer.integrations", @@ -21,9 +21,7 @@ const WipeMyCalActionButton = (props: IWipeMyCalActionButtonProps) => { if (bookingStatus !== "upcoming" || bookingsEmpty) { return <>; } - const wipeMyCalCredentials: { credentialIds: number[] } = data?.items.find( - (item: { type: string }) => item.type === "wipemycal_other" - ); + const wipeMyCalCredentials = data?.items.find((item: { type: string }) => item.type === "wipemycal_other"); const [credentialId] = wipeMyCalCredentials?.credentialIds || [false]; @@ -31,7 +29,7 @@ const WipeMyCalActionButton = (props: IWipeMyCalActionButtonProps) => {
{data && isSuccess && !isLoading && credentialId && ( <> - + diff --git a/packages/app-store/zapier/pages/setup/index.tsx b/packages/app-store/zapier/pages/setup/index.tsx index ac2e13a071..27c8fc11fe 100644 --- a/packages/app-store/zapier/pages/setup/index.tsx +++ b/packages/app-store/zapier/pages/setup/index.tsx @@ -6,11 +6,9 @@ import { Toaster } from "react-hot-toast"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; +import { trpc } from "@calcom/trpc/react"; import { Button, Loader, Tooltip } from "@calcom/ui"; -/** TODO: Maybe extract this into a package to prevent circular dependencies */ -import { trpc } from "@calcom/web/lib/trpc"; - export interface IZapierSetupProps { inviteLink: string; } @@ -21,11 +19,7 @@ export default function ZapierSetup(props: IZapierSetupProps) { const [newApiKey, setNewApiKey] = useState(""); const { t } = useLocale(); const utils = trpc.useContext(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore const integrations = trpc.useQuery(["viewer.integrations", { variant: "other" }]); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore const oldApiKey = trpc.useQuery(["viewer.apiKeys.findKeyOfType", { appId: ZAPIER }]); const deleteApiKey = trpc.useMutation("viewer.apiKeys.delete"); @@ -38,8 +32,6 @@ export default function ZapierSetup(props: IZapierSetupProps) { async function createApiKey() { const event = { note: "Zapier", expiresAt: null, appId: ZAPIER }; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore const apiKey = await utils.client.mutation("viewer.apiKeys.create", event); if (oldApiKey.data) { deleteApiKey.mutate({ diff --git a/packages/config/next-i18next.config.js b/packages/config/next-i18next.config.js new file mode 100644 index 0000000000..c0c2c65203 --- /dev/null +++ b/packages/config/next-i18next.config.js @@ -0,0 +1,35 @@ +const path = require("path"); + +/** @type {import("next-i18next").UserConfig} */ +const config = { + i18n: { + defaultLocale: "en", + locales: [ + "en", + "fr", + "it", + "ru", + "es", + "de", + "pt", + "ro", + "nl", + "pt-BR", + "es-419", + "ko", + "ja", + "pl", + "ar", + "iw", + "zh-CN", + "zh-TW", + "cs", + "sr", + "sv", + "vi", + ], + }, + reloadOnPrerender: process.env.NODE_ENV !== "production", +}; + +module.exports = config; diff --git a/packages/emails/templates/attendee-request-reschedule-email.ts b/packages/emails/templates/attendee-request-reschedule-email.ts index fbc842e434..2a325a79cc 100644 --- a/packages/emails/templates/attendee-request-reschedule-email.ts +++ b/packages/emails/templates/attendee-request-reschedule-email.ts @@ -2,7 +2,7 @@ import { createEvent, DateArray, Person } from "ics"; import dayjs from "@calcom/dayjs"; import { getCancelLink } from "@calcom/lib/CalEventParser"; -import { CalendarEvent } from "@calcom/types/Calendar"; +import type { CalendarEvent } from "@calcom/types/Calendar"; import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; diff --git a/packages/emails/templates/organizer-request-reschedule-email.ts b/packages/emails/templates/organizer-request-reschedule-email.ts index 06d6b77d4f..452c3489a3 100644 --- a/packages/emails/templates/organizer-request-reschedule-email.ts +++ b/packages/emails/templates/organizer-request-reschedule-email.ts @@ -2,7 +2,7 @@ import { createEvent, DateArray, Person } from "ics"; import dayjs from "@calcom/dayjs"; import { getRichDescription } from "@calcom/lib/CalEventParser"; -import { CalendarEvent } from "@calcom/types/Calendar"; +import type { CalendarEvent } from "@calcom/types/Calendar"; import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; diff --git a/packages/lib/auth.ts b/packages/lib/auth.ts index 976b6c32ce..852592bc11 100644 --- a/packages/lib/auth.ts +++ b/packages/lib/auth.ts @@ -1,4 +1,6 @@ import { compare, hash } from "bcryptjs"; +import { Session } from "next-auth"; +import { getSession as getSessionInner, GetSessionParams } from "next-auth/react"; export async function hashPassword(password: string) { const hashedPassword = await hash(password, 12); @@ -9,3 +11,10 @@ export async function verifyPassword(password: string, hashedPassword: string) { const isValid = await compare(password, hashedPassword); return isValid; } + +export async function getSession(options: GetSessionParams): Promise { + const session = await getSessionInner(options); + + // that these are equal are ensured in `[...nextauth]`'s callback + return session as Session | null; +} diff --git a/packages/lib/i18n.ts b/packages/lib/i18n.ts new file mode 100644 index 0000000000..33b1e82aaa --- /dev/null +++ b/packages/lib/i18n.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +import parser from "accept-language-parser"; +import { IncomingMessage } from "http"; + +import prisma from "@calcom/prisma"; +import { Maybe } from "@calcom/trpc/server"; + +import { getSession } from "./auth"; + +const { i18n } = require("@calcom/config/next-i18next.config"); + +export function getLocaleFromHeaders(req: IncomingMessage): string { + let preferredLocale: string | null | undefined; + if (req.headers["accept-language"]) { + preferredLocale = parser.pick(i18n.locales, req.headers["accept-language"]) as Maybe; + } + return preferredLocale ?? i18n.defaultLocale; +} + +export const getOrSetUserLocaleFromHeaders = async (req: IncomingMessage): Promise => { + const session = await getSession({ req }); + const preferredLocale = getLocaleFromHeaders(req); + + if (session?.user?.id) { + const user = await prisma.user.findUnique({ + where: { + id: session.user.id, + }, + select: { + locale: true, + }, + }); + + if (user?.locale) { + return user.locale; + } + + await prisma.user.update({ + where: { + id: session.user.id, + }, + data: { + locale: preferredLocale, + }, + }); + } + + return preferredLocale; +}; diff --git a/packages/lib/isOutOfBounds.tsx b/packages/lib/isOutOfBounds.tsx new file mode 100644 index 0000000000..1a115f737d --- /dev/null +++ b/packages/lib/isOutOfBounds.tsx @@ -0,0 +1,41 @@ +import { EventType, PeriodType } from "@prisma/client"; + +import dayjs from "@calcom/dayjs"; + +function isOutOfBounds( + time: dayjs.ConfigType, + { + periodType, + periodDays, + periodCountCalendarDays, + periodStartDate, + periodEndDate, + }: Pick< + EventType, + "periodType" | "periodDays" | "periodCountCalendarDays" | "periodStartDate" | "periodEndDate" + > +) { + const date = dayjs(time); + periodDays = periodDays || 0; + + switch (periodType) { + case PeriodType.ROLLING: { + const periodRollingEndDay = periodCountCalendarDays + ? dayjs().utcOffset(date.utcOffset()).add(periodDays, "days").endOf("day") + : dayjs().utcOffset(date.utcOffset()).businessDaysAdd(periodDays).endOf("day"); + return date.endOf("day").isAfter(periodRollingEndDay); + } + + case PeriodType.RANGE: { + const periodRangeStartDay = dayjs(periodStartDate).utcOffset(date.utcOffset()).endOf("day"); + const periodRangeEndDay = dayjs(periodEndDate).utcOffset(date.utcOffset()).endOf("day"); + return date.endOf("day").isBefore(periodRangeStartDay) || date.endOf("day").isAfter(periodRangeEndDay); + } + + case PeriodType.UNLIMITED: + default: + return false; + } +} + +export default isOutOfBounds; diff --git a/packages/lib/jackson.ts b/packages/lib/jackson.ts new file mode 100644 index 0000000000..7888e905ca --- /dev/null +++ b/packages/lib/jackson.ts @@ -0,0 +1,40 @@ +import jackson, { IAPIController, IOAuthController, JacksonOption } from "@boxyhq/saml-jackson"; + +import { WEBAPP_URL } from "./constants"; +import { samlDatabaseUrl } from "./saml"; + +// Set the required options. Refer to https://github.com/boxyhq/jackson#configuration for the full list +const opts: JacksonOption = { + externalUrl: WEBAPP_URL, + samlPath: "/api/auth/saml/callback", + db: { + engine: "sql", + type: "postgres", + url: samlDatabaseUrl, + encryptionKey: process.env.CALENDSO_ENCRYPTION_KEY, + }, + samlAudience: "https://saml.cal.com", +}; + +let apiController: IAPIController; +let oauthController: IOAuthController; + +const g = global as any; + +export default async function init() { + if (!g.apiController || !g.oauthController) { + const ret = await jackson(opts); + apiController = ret.apiController; + oauthController = ret.oauthController; + g.apiController = apiController; + g.oauthController = oauthController; + } else { + apiController = g.apiController; + oauthController = g.oauthController; + } + + return { + apiController, + oauthController, + }; +} diff --git a/packages/lib/package.json b/packages/lib/package.json index 89f2f0e4c2..2963e09239 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@calcom/dayjs": "*", + "@calcom/config": "*", "@prisma/client": "^4.1.0", "bcryptjs": "^2.4.3", "ical.js": "^1.4.0", diff --git a/packages/lib/profile.ts b/packages/lib/profile.ts new file mode 100644 index 0000000000..2ef123d980 --- /dev/null +++ b/packages/lib/profile.ts @@ -0,0 +1,11 @@ +import crypto from "crypto"; + +export const defaultAvatarSrc = function ({ email, md5 }: { md5?: string; email?: string }) { + if (!email && !md5) return ""; + + if (email && !md5) { + md5 = crypto.createHash("md5").update(email).digest("hex"); + } + + return `https://www.gravatar.com/avatar/${md5}?s=160&d=identicon&r=PG`; +}; diff --git a/packages/lib/saml.ts b/packages/lib/saml.ts new file mode 100644 index 0000000000..57cb0a997e --- /dev/null +++ b/packages/lib/saml.ts @@ -0,0 +1,59 @@ +import { PrismaClient } from "@prisma/client"; + +import { TRPCError } from "@calcom/trpc/server"; + +import { WEBAPP_URL } from "./constants"; + +export const samlDatabaseUrl = process.env.SAML_DATABASE_URL || ""; +export const samlLoginUrl = WEBAPP_URL; + +export const isSAMLLoginEnabled = samlDatabaseUrl.length > 0; + +export const samlTenantID = "Cal.com"; +export const samlProductID = "Cal.com"; + +const samlAdmins = (process.env.SAML_ADMINS || "").split(","); +export const hostedCal = WEBAPP_URL === "https://app.cal.com"; +export const tenantPrefix = "team-"; + +export const isSAMLAdmin = (email: string) => { + for (const admin of samlAdmins) { + if (admin.toLowerCase() === email.toLowerCase() && admin.toUpperCase() === email.toUpperCase()) { + return true; + } + } + + return false; +}; + +export const samlTenantProduct = async (prisma: PrismaClient, email: string) => { + const user = await prisma.user.findUnique({ + where: { + email, + }, + select: { + id: true, + invitedTo: true, + }, + }); + + if (!user) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Unauthorized Request", + }); + } + + if (!user.invitedTo) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: + "Could not find a SAML Identity Provider for your email. Please contact your admin to ensure you have been given access to Cal", + }); + } + + return { + tenant: tenantPrefix + user.invitedTo, + product: samlProductID, + }; +}; diff --git a/apps/web/lib/core/server/checkRegularUsername.ts b/packages/lib/server/checkRegularUsername.ts similarity index 86% rename from apps/web/lib/core/server/checkRegularUsername.ts rename to packages/lib/server/checkRegularUsername.ts index 6fd6dcdb4c..e467809dba 100644 --- a/apps/web/lib/core/server/checkRegularUsername.ts +++ b/packages/lib/server/checkRegularUsername.ts @@ -1,5 +1,5 @@ -import prisma from "@lib/prisma"; -import slugify from "@lib/slugify"; +import slugify from "@calcom/lib/slugify"; +import prisma from "@calcom/prisma"; export async function checkRegularUsername(_username: string) { const username = slugify(_username); diff --git a/apps/web/lib/core/server/checkUsername.ts b/packages/lib/server/checkUsername.ts similarity index 74% rename from apps/web/lib/core/server/checkUsername.ts rename to packages/lib/server/checkUsername.ts index 579686488c..dce2b1f47b 100644 --- a/apps/web/lib/core/server/checkUsername.ts +++ b/packages/lib/server/checkUsername.ts @@ -1,6 +1,6 @@ import { checkPremiumUsername } from "@calcom/ee/lib/core/checkPremiumUsername"; import { IS_SELF_HOSTED } from "@calcom/lib/constants"; -import { checkRegularUsername } from "@lib/core/server/checkRegularUsername"; +import { checkRegularUsername } from "./checkRegularUsername"; export const checkUsername = IS_SELF_HOSTED ? checkRegularUsername : checkPremiumUsername; diff --git a/packages/lib/server/queries/index.ts b/packages/lib/server/queries/index.ts new file mode 100644 index 0000000000..9a4630082b --- /dev/null +++ b/packages/lib/server/queries/index.ts @@ -0,0 +1 @@ +export * from "./teams"; diff --git a/apps/web/lib/queries/teams/index.ts b/packages/lib/server/queries/teams/index.ts similarity index 95% rename from apps/web/lib/queries/teams/index.ts rename to packages/lib/server/queries/teams/index.ts index 7b3c2f3932..a168f3361f 100644 --- a/apps/web/lib/queries/teams/index.ts +++ b/packages/lib/server/queries/teams/index.ts @@ -1,8 +1,6 @@ import { Prisma, UserPlan } from "@prisma/client"; -import { baseEventTypeSelect } from "@calcom/prisma"; - -import prisma from "@lib/prisma"; +import prisma, { baseEventTypeSelect } from "@calcom/prisma"; export type TeamWithMembers = Awaited>; diff --git a/packages/lib/slots.ts b/packages/lib/slots.ts new file mode 100644 index 0000000000..1e46accbc0 --- /dev/null +++ b/packages/lib/slots.ts @@ -0,0 +1,114 @@ +import dayjs, { Dayjs } from "@calcom/dayjs"; +import { WorkingHours } from "@calcom/types/schedule"; + +import { getWorkingHours } from "./availability"; + +export type GetSlots = { + inviteeDate: Dayjs; + frequency: number; + workingHours: WorkingHours[]; + minimumBookingNotice: number; + eventLength: number; +}; +export type WorkingHoursTimeFrame = { startTime: number; endTime: number }; + +const splitAvailableTime = ( + startTimeMinutes: number, + endTimeMinutes: number, + frequency: number, + eventLength: number +): Array => { + let initialTime = startTimeMinutes; + const finalizationTime = endTimeMinutes; + const result = [] as Array; + while (initialTime < finalizationTime) { + const periodTime = initialTime + frequency; + const slotEndTime = initialTime + eventLength; + /* + check if the slot end time surpasses availability end time of the user + 1 minute is added to round up the hour mark so that end of the slot is considered in the check instead of x9 + eg: if finalization time is 11:59, slotEndTime is 12:00, we ideally want the slot to be available + */ + if (slotEndTime <= finalizationTime + 1) result.push({ startTime: initialTime, endTime: periodTime }); + initialTime += frequency; + } + return result; +}; + +const getSlots = ({ inviteeDate, frequency, minimumBookingNotice, workingHours, eventLength }: GetSlots) => { + // current date in invitee tz + const startDate = dayjs().add(minimumBookingNotice, "minute"); + const startOfDay = dayjs.utc().startOf("day"); + const startOfInviteeDay = inviteeDate.startOf("day"); + // checks if the start date is in the past + + /** + * TODO: change "day" for "hour" to stop displaying 1 day before today + * This is displaying a day as available as sometimes difference between two dates is < 24 hrs. + * But when doing timezones an available day for an owner can be 2 days available in other users tz. + * + * */ + if (inviteeDate.isBefore(startDate, "day")) { + return []; + } + + const localWorkingHours = getWorkingHours( + { utcOffset: -inviteeDate.utcOffset() }, + workingHours.map((schedule) => ({ + days: schedule.days, + startTime: startOfDay.add(schedule.startTime, "minute"), + endTime: startOfDay.add(schedule.endTime, "minute"), + })) + ).filter((hours) => hours.days.includes(inviteeDate.day())); + + const slots: Dayjs[] = []; + + const slotsTimeFrameAvailable = [] as Array; + // Here we split working hour in chunks for every frequency available that can fit in whole working hours + const computedLocalWorkingHours: WorkingHoursTimeFrame[] = []; + let tempComputeTimeFrame: WorkingHoursTimeFrame | undefined; + const computeLength = localWorkingHours.length - 1; + const makeTimeFrame = (item: typeof localWorkingHours[0]): WorkingHoursTimeFrame => ({ + startTime: item.startTime, + endTime: item.endTime, + }); + localWorkingHours.forEach((item, index) => { + if (!tempComputeTimeFrame) { + tempComputeTimeFrame = makeTimeFrame(item); + } else { + // please check the comment in splitAvailableTime func for the added 1 minute + if (tempComputeTimeFrame.endTime + 1 === item.startTime) { + // to deal with time that across the day, e.g. from 11:59 to to 12:01 + tempComputeTimeFrame.endTime = item.endTime; + } else { + computedLocalWorkingHours.push(tempComputeTimeFrame); + tempComputeTimeFrame = makeTimeFrame(item); + } + } + if (index == computeLength) { + computedLocalWorkingHours.push(tempComputeTimeFrame); + } + }); + computedLocalWorkingHours.forEach((item) => { + slotsTimeFrameAvailable.push(...splitAvailableTime(item.startTime, item.endTime, frequency, eventLength)); + }); + + slotsTimeFrameAvailable.forEach((item) => { + const slot = startOfInviteeDay.add(item.startTime, "minute"); + // Validating slot its not on the past + if (!slot.isBefore(startDate)) { + slots.push(slot); + } + }); + + const uniq = (a: Dayjs[]) => { + const seen: Record = {}; + return a.filter((item) => { + return seen.hasOwnProperty(item.format()) ? false : (seen[item.format()] = true); + }); + }; + + return uniq(slots); +}; + +export default getSlots; diff --git a/packages/lib/tsconfig.json b/packages/lib/tsconfig.json index 218a8b1355..c35e0c6de3 100644 --- a/packages/lib/tsconfig.json +++ b/packages/lib/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "target": "es5" }, - "include": ["."], + "include": [".", "../types/next-auth.d.ts"], "exclude": ["dist", "build", "node_modules"] } diff --git a/packages/lib/webhooks/constants.ts b/packages/lib/webhooks/constants.ts new file mode 100644 index 0000000000..ee02568bce --- /dev/null +++ b/packages/lib/webhooks/constants.ts @@ -0,0 +1,17 @@ +import { WebhookTriggerEvents } from "@prisma/client"; + +// this is exported as we can't use `WebhookTriggerEvents` in the frontend straight-off + +export const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP = { + core: [ + WebhookTriggerEvents.BOOKING_CANCELLED, + WebhookTriggerEvents.BOOKING_CREATED, + WebhookTriggerEvents.BOOKING_RESCHEDULED, + ] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"], + routing_forms: [WebhookTriggerEvents.FORM_SUBMITTED] as ["FORM_SUBMITTED"], +}; + +export const WEBHOOK_TRIGGER_EVENTS = [ + ...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP.core, + ...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP.routing_forms, +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED", "FORM_SUBMITTED"]; diff --git a/packages/lib/webhooks/integrationTemplate.tsx b/packages/lib/webhooks/integrationTemplate.tsx new file mode 100644 index 0000000000..a461789cb9 --- /dev/null +++ b/packages/lib/webhooks/integrationTemplate.tsx @@ -0,0 +1,28 @@ +const supportedWebhookIntegrationList = ["https://discord.com/api/webhooks/"]; + +type WebhookIntegrationProps = { + url: string; +}; + +export const hasTemplateIntegration = (props: WebhookIntegrationProps) => { + const ind = supportedWebhookIntegrationList.findIndex((integration) => { + return props.url.includes(integration); + }); + return ind > -1; +}; + +const customTemplate = (props: WebhookIntegrationProps) => { + const ind = supportedWebhookIntegrationList.findIndex((integration) => { + return props.url.includes(integration); + }); + return integrationTemplate(supportedWebhookIntegrationList[ind]) || ""; +}; + +const integrationTemplate = (webhookIntegration: string) => { + switch (webhookIntegration) { + case "https://discord.com/api/webhooks/": + return '{"content": "An event has been scheduled/updated","embeds": [{"color": 2697513,"fields": [{"name": "Event Trigger","value": "{{triggerEvent}}"}, {"name": "What","value": "{{title}} ({{type}})"},{"name": "When","value": "Start: {{startTime}} \\n End: {{endTime}} \\n Timezone: ({{organizer.timeZone}})"},{"name": "Who","value": "Organizer: {{organizer.name}} ({{organizer.email}}) \\n Booker: {{attendees.0.name}} ({{attendees.0.email}})" },{"name":"Description", "value":": {{description}}"},{"name":"Where","value":": {{location}} "}]}]}'; + } +}; + +export default customTemplate; diff --git a/packages/lib/webhooks/sendPayload.tsx b/packages/lib/webhooks/sendPayload.tsx new file mode 100644 index 0000000000..5eb1d019cf --- /dev/null +++ b/packages/lib/webhooks/sendPayload.tsx @@ -0,0 +1,108 @@ +import { Webhook } from "@prisma/client"; +import { createHmac } from "crypto"; +import { compile } from "handlebars"; + +import type { CalendarEvent } from "@calcom/types/Calendar"; + +type ContentType = "application/json" | "application/x-www-form-urlencoded"; + +function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { + const compiled = compile(template)(data); + if (contentType === "application/json") { + return JSON.stringify(jsonParse(compiled)); + } + return compiled; +} + +function jsonParse(jsonString: string) { + try { + return JSON.parse(jsonString); + } catch (e) { + // don't do anything. + } + return false; +} + +const sendPayload = async ( + secretKey: string | null, + triggerEvent: string, + createdAt: string, + webhook: Pick, + data: CalendarEvent & { + metadata?: { [key: string]: string }; + rescheduleUid?: string; + bookingId?: number; + } +) => { + const { appId, payloadTemplate: template } = webhook; + + const contentType = + !template || jsonParse(template) ? "application/json" : "application/x-www-form-urlencoded"; + + data.description = data.description || data.additionalNotes; + + let body; + + /* Zapier id is hardcoded in the DB, we send the raw data for this case */ + if (appId === "zapier") { + body = JSON.stringify(data); + } else if (template) { + body = applyTemplate(template, data, contentType); + } else { + body = JSON.stringify({ + triggerEvent: triggerEvent, + createdAt: createdAt, + payload: data, + }); + } + + return _sendPayload(secretKey, triggerEvent, createdAt, webhook, body, contentType); +}; + +export const sendGenericWebhookPayload = async ( + secretKey: string | null, + triggerEvent: string, + createdAt: string, + webhook: Pick, + data: Record +) => { + const body = JSON.stringify(data); + return _sendPayload(secretKey, triggerEvent, createdAt, webhook, body, "application/json"); +}; + +const _sendPayload = async ( + secretKey: string | null, + triggerEvent: string, + createdAt: string, + webhook: Pick, + body: string, + contentType: "application/json" | "application/x-www-form-urlencoded" +) => { + const { subscriberUrl } = webhook; + if (!subscriberUrl || !body) { + throw new Error("Missing required elements to send webhook payload."); + } + + const secretSignature = secretKey + ? createHmac("sha256", secretKey).update(`${body}`).digest("hex") + : "no-secret-provided"; + + const response = await fetch(subscriberUrl, { + method: "POST", + headers: { + "Content-Type": contentType, + "X-Cal-Signature-256": secretSignature, + }, + body, + }); + + const text = await response.text(); + + return { + ok: response.ok, + status: response.status, + message: text, + }; +}; + +export default sendPayload; diff --git a/packages/lib/webhooks/subscriptions.tsx b/packages/lib/webhooks/subscriptions.tsx new file mode 100644 index 0000000000..67fd8f53db --- /dev/null +++ b/packages/lib/webhooks/subscriptions.tsx @@ -0,0 +1,43 @@ +import { WebhookTriggerEvents } from "@prisma/client"; + +import prisma from "@calcom/prisma"; + +export type GetSubscriberOptions = { + userId: number; + eventTypeId: number; + triggerEvent: WebhookTriggerEvents; +}; + +const getWebhooks = async (options: GetSubscriberOptions) => { + const { userId, eventTypeId } = options; + const allWebhooks = await prisma.webhook.findMany({ + where: { + OR: [ + { + userId, + }, + { + eventTypeId, + }, + ], + AND: { + eventTriggers: { + has: options.triggerEvent, + }, + active: { + equals: true, + }, + }, + }, + select: { + subscriberUrl: true, + payloadTemplate: true, + appId: true, + secret: true, + }, + }); + + return allWebhooks; +}; + +export default getWebhooks; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index b6a84f337c..752857ef33 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -19,14 +19,14 @@ generator zod { } enum SchedulingType { - ROUND_ROBIN @map("roundRobin") - COLLECTIVE @map("collective") + ROUND_ROBIN @map("roundRobin") + COLLECTIVE @map("collective") } enum PeriodType { - UNLIMITED @map("unlimited") - ROLLING @map("rolling") - RANGE @map("range") + UNLIMITED @map("unlimited") + ROLLING @map("rolling") + RANGE @map("range") } model EventType { @@ -253,10 +253,10 @@ model Attendee { } enum BookingStatus { - CANCELLED @map("cancelled") - ACCEPTED @map("accepted") - REJECTED @map("rejected") - PENDING @map("pending") + CANCELLED @map("cancelled") + ACCEPTED @map("accepted") + REJECTED @map("rejected") + PENDING @map("pending") } model DailyEventReference { @@ -335,10 +335,10 @@ model SelectedCalendar { } enum EventTypeCustomInputType { - TEXT @map("text") - TEXTLONG @map("textLong") - NUMBER @map("number") - BOOL @map("bool") + TEXT @map("text") + TEXTLONG @map("textLong") + NUMBER @map("number") + BOOL @map("bool") } model EventTypeCustomInput { @@ -575,9 +575,9 @@ model WorkflowsOnEventTypes { } enum TimeUnit { - DAY @map("day") - HOUR @map("hour") - MINUTE @map("minute") + DAY @map("day") + HOUR @map("hour") + MINUTE @map("minute") } model WorkflowReminder { diff --git a/packages/stripe/package.json b/packages/stripe/package.json index e302ee925c..cbf9c13460 100644 --- a/packages/stripe/package.json +++ b/packages/stripe/package.json @@ -11,12 +11,18 @@ "ts-node": "^10.6.0" }, "dependencies": { + "@calcom/app-store": "*", "@calcom/dayjs": "*", "@calcom/ee": "*", + "@calcom/emails": "*", "@calcom/lib": "*", + "@calcom/prisma": "*", + "@calcom/types": "*", "@stripe/react-stripe-js": "^1.8.0", "@stripe/stripe-js": "^1.29.0", - "stripe": "^9.1.0" + "stripe": "^9.1.0", + "uuid": "^8.3.2", + "zod": "^3.16.0" }, "main": "index.ts", "types": "index.d.ts", diff --git a/packages/stripe/server.ts b/packages/stripe/server.ts index 7194436a3e..0e4a3d0096 100644 --- a/packages/stripe/server.ts +++ b/packages/stripe/server.ts @@ -1,6 +1,16 @@ +import { PaymentType, Prisma } from "@prisma/client"; import Stripe from "stripe"; +import { v4 as uuidv4 } from "uuid"; import { z } from "zod"; +import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug"; +import { sendAwaitingPaymentEmail, sendOrganizerPaymentRefundFailedEmail } from "@calcom/emails"; +import { getErrorFromUnknown } from "@calcom/lib/errors"; +import prisma from "@calcom/prisma"; +import type { CalendarEvent } from "@calcom/types/Calendar"; + +import { createPaymentLink } from "./client"; + export type PaymentData = Stripe.Response & { stripe_publishable_key: string; stripeAccount: string; @@ -28,4 +38,173 @@ const stripe = new Stripe(stripePrivateKey, { apiVersion: "2020-08-27", }); +const stripeKeysSchema = z.object({ + payment_fee_fixed: z.number(), + payment_fee_percentage: z.number(), +}); + +const stripeCredentialSchema = z.object({ + stripe_user_id: z.string(), + stripe_publishable_key: z.string(), +}); + +export async function handlePayment( + evt: CalendarEvent, + selectedEventType: { + price: number; + currency: string; + }, + stripeCredential: { key: Prisma.JsonValue }, + booking: { + user: { email: string | null; name: string | null; timeZone: string } | null; + id: number; + startTime: { toISOString: () => string }; + uid: string; + } +) { + const appKeys = await getAppKeysFromSlug("stripe"); + const { payment_fee_fixed, payment_fee_percentage } = stripeKeysSchema.parse(appKeys); + + const paymentFee = Math.round(selectedEventType.price * payment_fee_percentage + payment_fee_fixed); + const { stripe_user_id, stripe_publishable_key } = stripeCredentialSchema.parse(stripeCredential.key); + + const params: Stripe.PaymentIntentCreateParams = { + amount: selectedEventType.price, + currency: selectedEventType.currency, + payment_method_types: ["card"], + application_fee_amount: paymentFee, + }; + + const paymentIntent = await stripe.paymentIntents.create(params, { stripeAccount: stripe_user_id }); + + const payment = await prisma.payment.create({ + data: { + type: PaymentType.STRIPE, + uid: uuidv4(), + booking: { + connect: { + id: booking.id, + }, + }, + amount: selectedEventType.price, + fee: paymentFee, + currency: selectedEventType.currency, + success: false, + refunded: false, + data: Object.assign({}, paymentIntent, { + stripe_publishable_key, + stripeAccount: stripe_user_id, + }) /* We should treat this */ as PaymentData /* but Prisma doesn't know how to handle it, so it we treat it */ as unknown /* and then */ as Prisma.InputJsonValue, + externalId: paymentIntent.id, + }, + }); + + await sendAwaitingPaymentEmail({ + ...evt, + paymentInfo: { + link: createPaymentLink({ + paymentUid: payment.uid, + name: booking.user?.name, + email: booking.user?.email, + date: booking.startTime.toISOString(), + }), + }, + }); + + return payment; +} + +export async function refund( + booking: { + id: number; + uid: string; + startTime: Date; + payment: { + id: number; + success: boolean; + refunded: boolean; + externalId: string; + data: Prisma.JsonValue; + type: PaymentType; + }[]; + }, + calEvent: CalendarEvent +) { + try { + const payment = booking.payment.find((e) => e.success && !e.refunded); + if (!payment) return; + + if (payment.type !== PaymentType.STRIPE) { + await handleRefundError({ + event: calEvent, + reason: "cannot refund non Stripe payment", + paymentId: "unknown", + }); + return; + } + + const refund = await stripe.refunds.create( + { + payment_intent: payment.externalId, + }, + { stripeAccount: (payment.data as unknown as PaymentData)["stripeAccount"] } + ); + + if (!refund || refund.status === "failed") { + await handleRefundError({ + event: calEvent, + reason: refund?.failure_reason || "unknown", + paymentId: payment.externalId, + }); + return; + } + + await prisma.payment.update({ + where: { + id: payment.id, + }, + data: { + refunded: true, + }, + }); + } catch (e) { + const err = getErrorFromUnknown(e); + console.error(err, "Refund failed"); + await handleRefundError({ + event: calEvent, + reason: err.message || "unknown", + paymentId: "unknown", + }); + } +} + +export const closePayments = async (paymentIntentId: string, stripeAccount: string) => { + try { + // Expire all current sessions + const sessions = await stripe.checkout.sessions.list( + { + payment_intent: paymentIntentId, + }, + { stripeAccount } + ); + for (const session of sessions.data) { + await stripe.checkout.sessions.expire(session.id, { stripeAccount }); + } + // Then cancel the payment intent + await stripe.paymentIntents.cancel(paymentIntentId, { stripeAccount }); + return; + } catch (e) { + console.error(e); + return; + } +}; + +async function handleRefundError(opts: { event: CalendarEvent; reason: string; paymentId: string }) { + console.error(`refund failed: ${opts.reason} for booking '${opts.event.uid}'`); + await sendOrganizerPaymentRefundFailedEmail({ + ...opts.event, + paymentInfo: { reason: opts.reason, id: opts.paymentId }, + }); +} + export default stripe; diff --git a/packages/trpc/client/index.ts b/packages/trpc/client/index.ts new file mode 100644 index 0000000000..475e75c7fb --- /dev/null +++ b/packages/trpc/client/index.ts @@ -0,0 +1 @@ +export * from "@trpc/client"; diff --git a/packages/trpc/client/links/httpBatchLink.ts b/packages/trpc/client/links/httpBatchLink.ts new file mode 100644 index 0000000000..382865905e --- /dev/null +++ b/packages/trpc/client/links/httpBatchLink.ts @@ -0,0 +1 @@ +export * from "@trpc/client/links/httpBatchLink"; diff --git a/packages/trpc/client/links/httpLink.ts b/packages/trpc/client/links/httpLink.ts new file mode 100644 index 0000000000..9afdba2f05 --- /dev/null +++ b/packages/trpc/client/links/httpLink.ts @@ -0,0 +1 @@ +export * from "@trpc/client/links/httpLink"; diff --git a/packages/trpc/client/links/loggerLink.ts b/packages/trpc/client/links/loggerLink.ts new file mode 100644 index 0000000000..cbf08ae39c --- /dev/null +++ b/packages/trpc/client/links/loggerLink.ts @@ -0,0 +1 @@ +export * from "@trpc/client/links/loggerLink"; diff --git a/packages/trpc/client/links/splitLink.ts b/packages/trpc/client/links/splitLink.ts new file mode 100644 index 0000000000..ce2279c13b --- /dev/null +++ b/packages/trpc/client/links/splitLink.ts @@ -0,0 +1 @@ +export * from "@trpc/client/links/splitLink"; diff --git a/packages/trpc/index.ts b/packages/trpc/index.ts new file mode 100644 index 0000000000..d03e008f51 --- /dev/null +++ b/packages/trpc/index.ts @@ -0,0 +1,4 @@ +export * from "./client"; +export * from "./next"; +export * from "./react"; +export * from "./server"; diff --git a/packages/trpc/next/index.ts b/packages/trpc/next/index.ts new file mode 100644 index 0000000000..89cfa7ca25 --- /dev/null +++ b/packages/trpc/next/index.ts @@ -0,0 +1 @@ +export * from "@trpc/next"; diff --git a/packages/trpc/package.json b/packages/trpc/package.json new file mode 100644 index 0000000000..bfc54f4c48 --- /dev/null +++ b/packages/trpc/package.json @@ -0,0 +1,15 @@ +{ + "name": "@calcom/trpc", + "description": "Shared tRPC library for Cal.com", + "authors": "zomars", + "version": "1.0.0", + "main": "index.ts", + "dependencies": { + "@trpc/client": "^9.25.2", + "@trpc/next": "^9.25.2", + "@trpc/react": "^9.25.2", + "@trpc/server": "^9.25.2", + "superjson": "1.9.1", + "zod": "^3.16.0" + } +} diff --git a/packages/trpc/react/index.ts b/packages/trpc/react/index.ts new file mode 100644 index 0000000000..e1abbf8870 --- /dev/null +++ b/packages/trpc/react/index.ts @@ -0,0 +1,2 @@ +export * from "@trpc/react"; +export * from "./trpc"; diff --git a/packages/trpc/react/ssg.ts b/packages/trpc/react/ssg.ts new file mode 100644 index 0000000000..dd0a894534 --- /dev/null +++ b/packages/trpc/react/ssg.ts @@ -0,0 +1 @@ +export * from "@trpc/react/ssg"; diff --git a/apps/web/lib/trpc.ts b/packages/trpc/react/trpc.ts similarity index 86% rename from apps/web/lib/trpc.ts rename to packages/trpc/react/trpc.ts index bf15bef5b1..c8ade47136 100644 --- a/apps/web/lib/trpc.ts +++ b/packages/trpc/react/trpc.ts @@ -1,10 +1,10 @@ -// ℹ️ Type-only import: -// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export import superjson from "superjson"; -import type { AppRouter } from "@server/routers/_app"; -import { createReactQueryHooks } from "@trpc/react"; -import type { inferProcedureOutput, inferProcedureInput } from "@trpc/server"; +import { createReactQueryHooks } from "../react"; +// ℹ️ Type-only import: +// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export +import type { inferProcedureInput, inferProcedureOutput } from "../server"; +import type { AppRouter } from "../server/routers/_app"; /** * A set of strongly-typed React hooks from your `AppRouter` type signature with `createReactQueryHooks`. diff --git a/packages/trpc/server/adapters/next.ts b/packages/trpc/server/adapters/next.ts new file mode 100644 index 0000000000..022b84d02b --- /dev/null +++ b/packages/trpc/server/adapters/next.ts @@ -0,0 +1 @@ +export * from "@trpc/server/adapters/next"; diff --git a/apps/web/server/createContext.ts b/packages/trpc/server/createContext.ts similarity index 95% rename from apps/web/server/createContext.ts rename to packages/trpc/server/createContext.ts index c57f1bbe97..6b7ea6f0e5 100644 --- a/apps/web/server/createContext.ts +++ b/packages/trpc/server/createContext.ts @@ -2,10 +2,11 @@ import { GetServerSidePropsContext } from "next"; import { Session } from "next-auth"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import { getSession } from "@lib/auth"; +import { getSession } from "@calcom/lib/auth"; +import { defaultAvatarSrc } from "@calcom/lib/profile"; +import prisma from "@calcom/prisma"; + import { getLocaleFromHeaders } from "@lib/core/i18n/i18n.utils"; -import prisma from "@lib/prisma"; -import { defaultAvatarSrc } from "@lib/profile"; import * as trpc from "@trpc/server"; import { Maybe } from "@trpc/server"; diff --git a/apps/web/server/createRouter.ts b/packages/trpc/server/createRouter.ts similarity index 100% rename from apps/web/server/createRouter.ts rename to packages/trpc/server/createRouter.ts diff --git a/packages/trpc/server/index.ts b/packages/trpc/server/index.ts new file mode 100644 index 0000000000..627b3705bf --- /dev/null +++ b/packages/trpc/server/index.ts @@ -0,0 +1 @@ +export * from "@trpc/server"; diff --git a/apps/web/server/routers/_app.ts b/packages/trpc/server/routers/_app.ts similarity index 100% rename from apps/web/server/routers/_app.ts rename to packages/trpc/server/routers/_app.ts diff --git a/apps/web/server/routers/viewer.tsx b/packages/trpc/server/routers/viewer.tsx similarity index 92% rename from apps/web/server/routers/viewer.tsx rename to packages/trpc/server/routers/viewer.tsx index 60f9799e47..897aab633a 100644 --- a/apps/web/server/routers/viewer.tsx +++ b/packages/trpc/server/routers/viewer.tsx @@ -1,4 +1,4 @@ -import { BookingStatus, MembershipRole, AppCategories, Prisma } from "@prisma/client"; +import { AppCategories, BookingStatus, MembershipRole, Prisma } from "@prisma/client"; import _ from "lodash"; import { JSONObject } from "superjson/dist/types"; import { z } from "zod"; @@ -7,18 +7,10 @@ import app_RoutingForms from "@calcom/app-store/ee/routing_forms/trpc-router"; import getApps, { getLocationOptions } from "@calcom/app-store/utils"; import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager"; import dayjs from "@calcom/dayjs"; -import { sendFeedbackEmail } from "@calcom/emails"; -import { sendCancelledEmails } from "@calcom/emails"; -import { parseRecurringEvent, isPrismaObjOrUndefined } from "@calcom/lib"; -import { baseEventTypeSelect, bookingMinimalSelect } from "@calcom/prisma"; -import stripe from "@calcom/stripe/server"; -import { closePayments } from "@ee/lib/stripe/server"; - -import { checkUsername } from "@lib/core/server/checkUsername"; -import hasKeyInMetadata from "@lib/hasKeyInMetadata"; -import jackson from "@lib/jackson"; -import prisma from "@lib/prisma"; -import { isTeamOwner } from "@lib/queries/teams"; +import { sendCancelledEmails, sendFeedbackEmail } from "@calcom/emails"; +import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib"; +import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata"; +import jackson from "@calcom/lib/jackson"; import { hostedCal, isSAMLAdmin, @@ -27,22 +19,26 @@ import { samlTenantID, samlTenantProduct, tenantPrefix, -} from "@lib/saml"; -import slugify from "@lib/slugify"; +} from "@calcom/lib/saml"; +import { checkUsername } from "@calcom/lib/server/checkUsername"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import { isTeamOwner } from "@calcom/lib/server/queries/teams"; +import slugify from "@calcom/lib/slugify"; +import prisma, { baseEventTypeSelect, bookingMinimalSelect } from "@calcom/prisma"; +import stripe, { closePayments } from "@calcom/stripe/server"; +import { resizeBase64Image } from "@calcom/web/server/lib/resizeBase64Image"; -import { getTranslation } from "@server/lib/i18n"; -import { apiKeysRouter } from "@server/routers/viewer/apiKeys"; -import { availabilityRouter } from "@server/routers/viewer/availability"; -import { bookingsRouter } from "@server/routers/viewer/bookings"; -import { eventTypesRouter } from "@server/routers/viewer/eventTypes"; -import { slotsRouter } from "@server/routers/viewer/slots"; -import { workflowsRouter } from "@server/routers/viewer/workflows"; import { TRPCError } from "@trpc/server"; import { createProtectedRouter, createRouter } from "../createRouter"; -import { resizeBase64Image } from "../lib/resizeBase64Image"; +import { apiKeysRouter } from "./viewer/apiKeys"; +import { availabilityRouter } from "./viewer/availability"; +import { bookingsRouter } from "./viewer/bookings"; +import { eventTypesRouter } from "./viewer/eventTypes"; +import { slotsRouter } from "./viewer/slots"; import { viewerTeamsRouter } from "./viewer/teams"; import { webhookRouter } from "./viewer/webhook"; +import { workflowsRouter } from "./viewer/workflows"; // things that unauthenticated users can query about themselves const publicViewerRouter = createRouter() @@ -314,59 +310,51 @@ const loggedInViewerRouter = createProtectedRouter() const skip = input.cursor ?? 0; const { prisma, user } = ctx; const bookingListingByStatus = input.status; - const bookingListingFilters: Record = { - upcoming: [ - { - endTime: { gte: new Date() }, - // These changes are needed to not show confirmed recurring events, - // as rescheduling or cancel for recurring event bookings should be - // handled separately for each occurrence - OR: [ - { - AND: [ - { NOT: { recurringEventId: { equals: null } } }, - { NOT: { status: { equals: BookingStatus.PENDING } } }, - { NOT: { status: { equals: BookingStatus.CANCELLED } } }, - { NOT: { status: { equals: BookingStatus.REJECTED } } }, - ], - }, - { - AND: [ - { recurringEventId: { equals: null } }, - { NOT: { status: { equals: BookingStatus.CANCELLED } } }, - { NOT: { status: { equals: BookingStatus.REJECTED } } }, - ], - }, - ], - }, - ], - recurring: [ - { - endTime: { gte: new Date() }, - AND: [ - { NOT: { recurringEventId: { equals: null } } }, - { NOT: { status: { equals: BookingStatus.CANCELLED } } }, - { NOT: { status: { equals: BookingStatus.REJECTED } } }, - ], - }, - ], - past: [ - { - endTime: { lte: new Date() }, - AND: [ - { NOT: { status: { equals: BookingStatus.CANCELLED } } }, - { NOT: { status: { equals: BookingStatus.REJECTED } } }, - ], - }, - ], - cancelled: [ - { - OR: [ - { status: { equals: BookingStatus.CANCELLED } }, - { status: { equals: BookingStatus.REJECTED } }, - ], - }, - ], + const bookingListingFilters: Record = { + upcoming: { + endTime: { gte: new Date() }, + // These changes are needed to not show confirmed recurring events, + // as rescheduling or cancel for recurring event bookings should be + // handled separately for each occurrence + OR: [ + { + AND: [ + { NOT: { recurringEventId: { equals: null } } }, + { + status: { + notIn: [BookingStatus.PENDING, BookingStatus.CANCELLED, BookingStatus.REJECTED], + }, + }, + ], + }, + { + AND: [ + { recurringEventId: { equals: null } }, + { status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] } }, + ], + }, + ], + }, + recurring: { + endTime: { gte: new Date() }, + AND: [ + { NOT: { recurringEventId: { equals: null } } }, + { status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] } }, + ], + }, + past: { + endTime: { lte: new Date() }, + AND: [ + { NOT: { status: { equals: BookingStatus.CANCELLED } } }, + { NOT: { status: { equals: BookingStatus.REJECTED } } }, + ], + }, + cancelled: { + OR: [ + { status: { equals: BookingStatus.CANCELLED } }, + { status: { equals: BookingStatus.REJECTED } }, + ], + }, }; const bookingListingOrderby: Record< typeof bookingListingByStatus, @@ -393,7 +381,7 @@ const loggedInViewerRouter = createProtectedRouter() }, }, ], - AND: passedBookingsFilter, + AND: [passedBookingsFilter], }, select: { ...bookingMinimalSelect, diff --git a/apps/web/server/routers/viewer/apiKeys.tsx b/packages/trpc/server/routers/viewer/apiKeys.tsx similarity index 98% rename from apps/web/server/routers/viewer/apiKeys.tsx rename to packages/trpc/server/routers/viewer/apiKeys.tsx index b11420f730..3c9bb04648 100644 --- a/apps/web/server/routers/viewer/apiKeys.tsx +++ b/packages/trpc/server/routers/viewer/apiKeys.tsx @@ -3,7 +3,7 @@ import { z } from "zod"; import { generateUniqueAPIKey } from "@calcom/ee/lib/api/apiKeys"; -import { createProtectedRouter } from "@server/createRouter"; +import { createProtectedRouter } from "../../createRouter"; export const apiKeysRouter = createProtectedRouter() .query("list", { diff --git a/apps/web/server/routers/viewer/availability.tsx b/packages/trpc/server/routers/viewer/availability.tsx similarity index 97% rename from apps/web/server/routers/viewer/availability.tsx rename to packages/trpc/server/routers/viewer/availability.tsx index be1a0bc668..51e6270cb1 100644 --- a/apps/web/server/routers/viewer/availability.tsx +++ b/packages/trpc/server/routers/viewer/availability.tsx @@ -1,12 +1,13 @@ import { Prisma } from "@prisma/client"; import { z } from "zod"; -import { getAvailabilityFromSchedule } from "@lib/availability"; -import { Schedule } from "@lib/types/schedule"; +import { getAvailabilityFromSchedule } from "@calcom/lib/availability"; +import { Schedule } from "@calcom/types/schedule"; -import { createProtectedRouter } from "@server/createRouter"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; + export const availabilityRouter = createProtectedRouter() .query("list", { async resolve({ ctx }) { diff --git a/apps/web/server/routers/viewer/bookings.tsx b/packages/trpc/server/routers/viewer/bookings.tsx similarity index 98% rename from apps/web/server/routers/viewer/bookings.tsx rename to packages/trpc/server/routers/viewer/bookings.tsx index ea19620ab8..65ba0de870 100644 --- a/apps/web/server/routers/viewer/bookings.tsx +++ b/packages/trpc/server/routers/viewer/bookings.tsx @@ -9,9 +9,10 @@ import logger from "@calcom/lib/logger"; import { getTranslation } from "@calcom/lib/server/i18n"; import type { AdditionalInformation, CalendarEvent } from "@calcom/types/Calendar"; -import { createProtectedRouter } from "@server/createRouter"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; + // Common data for all endpoints under webhook const commonBookingSchema = z.object({ bookingId: z.number(), diff --git a/apps/web/server/routers/viewer/eventTypes.tsx b/packages/trpc/server/routers/viewer/eventTypes.tsx similarity index 98% rename from apps/web/server/routers/viewer/eventTypes.tsx rename to packages/trpc/server/routers/viewer/eventTypes.tsx index 274074b76b..301c384147 100644 --- a/apps/web/server/routers/viewer/eventTypes.tsx +++ b/packages/trpc/server/routers/viewer/eventTypes.tsx @@ -8,10 +8,11 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; import { createEventTypeInput } from "@calcom/prisma/zod/custom/eventtype"; import { stripeDataSchema } from "@calcom/stripe/server"; -import { createProtectedRouter } from "@server/createRouter"; -import { viewerRouter } from "@server/routers/viewer"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; +import { viewerRouter } from "../viewer"; + function isPeriodType(keyInput: string): keyInput is PeriodType { return Object.keys(PeriodType).includes(keyInput); } diff --git a/apps/web/server/routers/viewer/slots.tsx b/packages/trpc/server/routers/viewer/slots.tsx similarity index 97% rename from apps/web/server/routers/viewer/slots.tsx rename to packages/trpc/server/routers/viewer/slots.tsx index 3ee1a7c11d..8d7f283f96 100644 --- a/apps/web/server/routers/viewer/slots.tsx +++ b/packages/trpc/server/routers/viewer/slots.tsx @@ -4,17 +4,16 @@ import { z } from "zod"; import type { CurrentSeats } from "@calcom/core/getUserAvailability"; import { getUserAvailability } from "@calcom/core/getUserAvailability"; import dayjs, { Dayjs } from "@calcom/dayjs"; +import isOutOfBounds from "@calcom/lib/isOutOfBounds"; import logger from "@calcom/lib/logger"; -import { prisma } from "@calcom/prisma"; -import { availabilityUserSelect } from "@calcom/prisma"; +import getSlots from "@calcom/lib/slots"; +import prisma, { availabilityUserSelect } from "@calcom/prisma"; import { TimeRange } from "@calcom/types/schedule"; -import isOutOfBounds from "@lib/isOutOfBounds"; -import getSlots from "@lib/slots"; - -import { createRouter } from "@server/createRouter"; import { TRPCError } from "@trpc/server"; +import { createRouter } from "../../createRouter"; + const getScheduleSchema = z .object({ // startTime ISOString diff --git a/apps/web/server/routers/viewer/teams.tsx b/packages/trpc/server/routers/viewer/teams.tsx similarity index 96% rename from apps/web/server/routers/viewer/teams.tsx rename to packages/trpc/server/routers/viewer/teams.tsx index f6e7238669..a9db87cc23 100644 --- a/apps/web/server/routers/viewer/teams.tsx +++ b/packages/trpc/server/routers/viewer/teams.tsx @@ -1,10 +1,13 @@ import { MembershipRole, Prisma, UserPlan } from "@prisma/client"; import { randomBytes } from "crypto"; -import { resolve } from "path"; import { z } from "zod"; import { getUserAvailability } from "@calcom/core/getUserAvailability"; import { sendTeamInviteEmail } from "@calcom/emails"; +import { HOSTED_CAL_FEATURES, WEBAPP_URL } from "@calcom/lib/constants"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import { getTeamWithMembers, isTeamAdmin, isTeamOwner } from "@calcom/lib/server/queries/teams"; +import slugify from "@calcom/lib/slugify"; import { availabilityUserSelect } from "@calcom/prisma"; import { addSeat, @@ -15,14 +18,10 @@ import { upgradeTeam, } from "@calcom/stripe/team-billing"; -import { BASE_URL, HOSTED_CAL_FEATURES } from "@lib/config/constants"; -import { getTeamWithMembers, isTeamAdmin, isTeamOwner } from "@lib/queries/teams"; -import slugify from "@lib/slugify"; - -import { createProtectedRouter } from "@server/createRouter"; -import { getTranslation } from "@server/lib/i18n"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; + export const viewerTeamsRouter = createProtectedRouter() // Retrieves team by id .query("get", { @@ -266,7 +265,9 @@ export const viewerTeamsRouter = createProtectedRouter() from: ctx.user.name, to: input.usernameOrEmail, teamName: team.name, - joinLink: `${BASE_URL}/auth/signup?token=${token}&callbackUrl=${BASE_URL + "/settings/teams"}`, + joinLink: `${WEBAPP_URL}/auth/signup?token=${token}&callbackUrl=${ + WEBAPP_URL + "/settings/teams" + }`, }); } } else { @@ -297,7 +298,7 @@ export const viewerTeamsRouter = createProtectedRouter() from: ctx.user.name, to: input.usernameOrEmail, teamName: team.name, - joinLink: BASE_URL + "/settings/teams", + joinLink: WEBAPP_URL + "/settings/teams", }); } } diff --git a/apps/web/server/routers/viewer/webhook.tsx b/packages/trpc/server/routers/viewer/webhook.tsx similarity index 96% rename from apps/web/server/routers/viewer/webhook.tsx rename to packages/trpc/server/routers/viewer/webhook.tsx index 39700287aa..047baf8603 100644 --- a/apps/web/server/routers/viewer/webhook.tsx +++ b/packages/trpc/server/routers/viewer/webhook.tsx @@ -3,14 +3,14 @@ import { v4 } from "uuid"; import { z } from "zod"; import { getErrorFromUnknown } from "@calcom/lib/errors"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import { WEBHOOK_TRIGGER_EVENTS } from "@calcom/lib/webhooks/constants"; +import sendPayload from "@calcom/lib/webhooks/sendPayload"; -import { WEBHOOK_TRIGGER_EVENTS } from "@lib/webhooks/constants"; -import sendPayload from "@lib/webhooks/sendPayload"; - -import { createProtectedRouter } from "@server/createRouter"; -import { getTranslation } from "@server/lib/i18n"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; + // Common data for all endpoints under webhook const webhookIdAndEventTypeIdSchema = z.object({ // Webhook ID diff --git a/apps/web/server/routers/viewer/workflows.tsx b/packages/trpc/server/routers/viewer/workflows.tsx similarity index 99% rename from apps/web/server/routers/viewer/workflows.tsx rename to packages/trpc/server/routers/viewer/workflows.tsx index b62793aa23..546743f5a0 100644 --- a/apps/web/server/routers/viewer/workflows.tsx +++ b/packages/trpc/server/routers/viewer/workflows.tsx @@ -24,9 +24,10 @@ import { scheduleSMSReminder, } from "@ee/lib/workflows/reminders/smsReminderManager"; -import { createProtectedRouter } from "@server/createRouter"; import { TRPCError } from "@trpc/server"; +import { createProtectedRouter } from "../../createRouter"; + export const workflowsRouter = createProtectedRouter() .query("list", { async resolve({ ctx }) {