diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index abb78cb8ce..fd7ed7332a 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -30,7 +30,8 @@ "**/*.tsx", ".next/types/**/*.ts", "../../packages/features/bookings/lib/getBookingInfo.ts", - "../../packages/features/bookings/lib/getUserBooking.ts" + "../../packages/features/bookings/lib/getUserBooking.ts", + "../../packages/features/Segment.tsx" ], "exclude": ["node_modules"] } diff --git a/apps/web/components/__tests__/Segment.test.tsx b/packages/features/Segment.test.tsx similarity index 98% rename from apps/web/components/__tests__/Segment.test.tsx rename to packages/features/Segment.test.tsx index 02abf78dd2..2cd26eb143 100644 --- a/apps/web/components/__tests__/Segment.test.tsx +++ b/packages/features/Segment.test.tsx @@ -2,12 +2,11 @@ import { render, screen, waitFor } from "@testing-library/react"; import { describe, expect, it, vi, beforeEach } from "vitest"; import type { Mock } from "vitest"; +import { Segment } from "@calcom/features/Segment"; import type { AttributesQueryValue } from "@calcom/lib/raqb/types"; import { AttributeType } from "@calcom/prisma/enums"; import { trpc, type RouterOutputs } from "@calcom/trpc"; -import { Segment } from "../Segment"; - type Attributes = RouterOutputs["viewer"]["appRoutingForms"]["getAttributesForTeam"]; type MatchingTeamMembersData = RouterOutputs["viewer"]["attributes"]["findTeamMembersMatchingAttributeLogic"]; const mockGetAttributesForTeam = ( diff --git a/apps/web/components/Segment.tsx b/packages/features/Segment.tsx similarity index 99% rename from apps/web/components/Segment.tsx rename to packages/features/Segment.tsx index 6cc90d2758..4c5af7407a 100644 --- a/apps/web/components/Segment.tsx +++ b/packages/features/Segment.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useCallback, useState } from "react"; import { Query, Builder, Utils as QbUtils } from "react-awesome-query-builder"; import type { ImmutableTree, BuilderProps } from "react-awesome-query-builder"; diff --git a/packages/features/eventtypes/components/AddMembersWithSwitch.tsx b/packages/features/eventtypes/components/AddMembersWithSwitch.tsx index 8e68d0c3de..be1ac93c40 100644 --- a/packages/features/eventtypes/components/AddMembersWithSwitch.tsx +++ b/packages/features/eventtypes/components/AddMembersWithSwitch.tsx @@ -1,15 +1,19 @@ -import type { ComponentProps, Dispatch, SetStateAction } from "react"; +import { useMemo, type ComponentProps, type Dispatch, type SetStateAction } from "react"; import { useFormContext } from "react-hook-form"; import { Controller } from "react-hook-form"; import type { Options } from "react-select"; +import { + useIsPlatform, + AddMembersWithSwitchWebWrapper, + AddMembersWithSwitchPlatformWrapper, +} from "@calcom/atoms/monorepo"; +import { Segment } from "@calcom/features/Segment"; import type { FormValues, Host, TeamMember } from "@calcom/features/eventtypes/lib/types"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { AttributesQueryValue } from "@calcom/lib/raqb/types"; -import { trpc } from "@calcom/trpc"; import { Label, SettingsToggle } from "@calcom/ui"; -import { Segment } from "../../../../apps/web/components/Segment"; import AssignAllTeamMembers from "./AssignAllTeamMembers"; import CheckedTeamSelect from "./CheckedTeamSelect"; import type { CheckedSelectOption } from "./CheckedTeamSelect"; @@ -122,7 +126,7 @@ function MembersSegmentWithToggle({ const onQueryValueChange = ({ queryValue }: { queryValue: AttributesQueryValue }) => { setRrSegmentQueryValue(queryValue); }; - + const isPlatform = useIsPlatform(); return ( name="assignRRMembersUsingSegment" @@ -136,19 +140,21 @@ function MembersSegmentWithToggle({ onCheckedChange={(active) => { setAssignRRMembersUsingSegment(active); }}> - + {!isPlatform && ( + + )} )} /> ); } -type AddMembersWithSwitchProps = { +export type AddMembersWithSwitchProps = { teamMembers: TeamMember[]; value: Host[]; onChange: (hosts: Host[]) => void; @@ -213,7 +219,7 @@ function useSegmentState() { }; } -function AddMembersWithSwitch({ +export function AddMembersWithSwitch({ teamMembers, value, onChange, @@ -243,11 +249,6 @@ function AddMembersWithSwitch({ isAssigningAllTeamMembersApplicable: automaticAddAllEnabled, isSegmentApplicable, }); - const utils = trpc.useUtils(); - - utils.viewer.appRoutingForms.getAttributesForTeam.prefetch({ - teamId, - }); const onAssignAllTeamMembersInactive = () => { setAssignRRMembersUsingSegment(false); @@ -318,10 +319,15 @@ const AddMembersWithSwitchWrapper = ({ }: AddMembersWithSwitchProps & { containerClassName?: string; }) => { + const isPlatform = useIsPlatform(); + const AddMembersWithSwitchWrapped = useMemo( + () => (isPlatform ? AddMembersWithSwitchPlatformWrapper : AddMembersWithSwitchWebWrapper), + [isPlatform] + ); return (
- +
); diff --git a/packages/features/eventtypes/components/CheckedTeamSelect.tsx b/packages/features/eventtypes/components/CheckedTeamSelect.tsx index e7ae2001bb..7ca4763c5a 100644 --- a/packages/features/eventtypes/components/CheckedTeamSelect.tsx +++ b/packages/features/eventtypes/components/CheckedTeamSelect.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useAutoAnimate } from "@formkit/auto-animate/react"; import { useState } from "react"; import type { Props } from "react-select"; diff --git a/packages/features/eventtypes/components/__tests__/AddMembersWithSwitch.test.tsx b/packages/features/eventtypes/components/__tests__/AddMembersWithSwitch.test.tsx index 9167cd0868..80dcb19032 100644 --- a/packages/features/eventtypes/components/__tests__/AddMembersWithSwitch.test.tsx +++ b/packages/features/eventtypes/components/__tests__/AddMembersWithSwitch.test.tsx @@ -4,7 +4,8 @@ import { FormProvider, useForm } from "react-hook-form"; import { describe, expect, it, vi } from "vitest"; import type { Host, TeamMember } from "../../lib/types"; -import AddMembersWithSwitch from "../AddMembersWithSwitch"; +import type { AddMembersWithSwitchProps } from "../AddMembersWithSwitch"; +import { AddMembersWithSwitch } from "../AddMembersWithSwitch"; // Mock matchMedia vi.mock("@formkit/auto-animate/react", () => ({ @@ -12,7 +13,7 @@ vi.mock("@formkit/auto-animate/react", () => ({ })); // Mock Segment component -vi.mock("@calcom/web/components/Segment", () => ({ +vi.mock("@calcom/features/Segment", () => ({ Segment: vi.fn().mockImplementation(({ onQueryValueChange }) => (
@@ -60,7 +61,7 @@ const renderComponent = ({ hosts: [], }, }: { - componentProps: Parameters[0]; + componentProps: AddMembersWithSwitchProps; formDefaultValues?: Record; }) => { const Wrapper = ({ children }: { children: React.ReactNode }) => { diff --git a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx index f0c7c2770a..f3f66c9adf 100644 --- a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx +++ b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx @@ -26,6 +26,7 @@ export type EventTeamAssignmentTabBaseProps = Pick< "teamMembers" | "team" | "eventType" > & { orgId: number | null; + isSegmentApplicable: boolean; }; export const mapMemberToChildrenOption = ( @@ -227,6 +228,7 @@ const RoundRobinHosts = ({ assignAllTeamMembers, setAssignAllTeamMembers, teamId, + isSegmentApplicable, }: { orgId: number | null; value: Host[]; @@ -235,6 +237,7 @@ const RoundRobinHosts = ({ assignAllTeamMembers: boolean; setAssignAllTeamMembers: Dispatch>; teamId: number; + isSegmentApplicable: boolean; }) => { const { t } = useLocale(); @@ -278,7 +281,7 @@ const RoundRobinHosts = ({ onChange={onChange} assignAllTeamMembers={assignAllTeamMembers} setAssignAllTeamMembers={setAssignAllTeamMembers} - isSegmentApplicable={!!orgId} + isSegmentApplicable={isSegmentApplicable} automaticAddAllEnabled={true} isRRWeightsEnabled={isRRWeightsEnabled} isFixed={false} @@ -347,12 +350,14 @@ const Hosts = ({ teamMembers, assignAllTeamMembers, setAssignAllTeamMembers, + isSegmentApplicable, }: { orgId: number | null; teamId: number; teamMembers: TeamMember[]; assignAllTeamMembers: boolean; setAssignAllTeamMembers: Dispatch>; + isSegmentApplicable: boolean; }) => { const { control, @@ -439,6 +444,7 @@ const Hosts = ({ }} assignAllTeamMembers={assignAllTeamMembers} setAssignAllTeamMembers={setAssignAllTeamMembers} + isSegmentApplicable={isSegmentApplicable} /> ), @@ -455,6 +461,7 @@ export const EventTeamAssignmentTab = ({ teamMembers, eventType, orgId, + isSegmentApplicable, }: EventTeamAssignmentTabBaseProps) => { const { t } = useLocale(); @@ -572,6 +579,7 @@ export const EventTeamAssignmentTab = ({
; -export const EventSetupTab = (props: EventSetupTabProps & { urlPrefix: string; hasOrgBranding: boolean }) => { +export const EventSetupTab = ( + props: EventSetupTabProps & { urlPrefix: string; hasOrgBranding: boolean; orgId?: number } +) => { const { t } = useLocale(); - const session = useSession(); const isPlatform = useIsPlatform(); const formMethods = useFormContext(); - const { eventType, team, urlPrefix, hasOrgBranding } = props; + const { eventType, team, urlPrefix, hasOrgBranding, orgId } = props; const [multipleDuration, setMultipleDuration] = useState( formMethods.getValues("metadata")?.multipleDuration ); @@ -105,8 +105,8 @@ export const EventSetupTab = (props: EventSetupTabProps & { urlPrefix: string; h onCheckedChange={(value) => { formMethods.setValue("autoTranslateDescriptionEnabled", value, { shouldDirty: true }); }} - disabled={!session.data?.user.org?.id} - tooltip={!session.data?.user.org?.id ? t("orgs_upgrade_to_enable_feature") : undefined} + disabled={!orgId} + tooltip={!orgId ? t("orgs_upgrade_to_enable_feature") : undefined} /> { + return ; +}; diff --git a/packages/platform/atoms/add-members-switch/AddMembersWithSwitchWebWrapper.tsx b/packages/platform/atoms/add-members-switch/AddMembersWithSwitchWebWrapper.tsx new file mode 100644 index 0000000000..1720fb54b2 --- /dev/null +++ b/packages/platform/atoms/add-members-switch/AddMembersWithSwitchWebWrapper.tsx @@ -0,0 +1,12 @@ +import type { AddMembersWithSwitchProps } from "@calcom/features/eventtypes/components/AddMembersWithSwitch"; +import { AddMembersWithSwitch } from "@calcom/features/eventtypes/components/AddMembersWithSwitch"; +import { trpc } from "@calcom/trpc"; + +export const AddMembersWithSwitchWebWrapper = ({ ...props }: AddMembersWithSwitchProps) => { + const utils = trpc.useUtils(); + + utils.viewer.appRoutingForms.getAttributesForTeam.prefetch({ + teamId: props.teamId, + }); + return ; +}; diff --git a/packages/platform/atoms/event-types/wrappers/EventSetupTabWebWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventSetupTabWebWrapper.tsx index cc23eb0661..b424bac22f 100644 --- a/packages/platform/atoms/event-types/wrappers/EventSetupTabWebWrapper.tsx +++ b/packages/platform/atoms/event-types/wrappers/EventSetupTabWebWrapper.tsx @@ -1,3 +1,5 @@ +import { useSession } from "next-auth/react"; + import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider"; import type { EventSetupTabProps } from "@calcom/features/eventtypes/components/tabs/setup/EventSetupTab"; import { EventSetupTab } from "@calcom/features/eventtypes/components/tabs/setup/EventSetupTab"; @@ -5,10 +7,18 @@ import { WEBSITE_URL } from "@calcom/lib/constants"; const EventSetupTabWebWrapper = (props: EventSetupTabProps) => { const orgBranding = useOrgBranding(); + const session = useSession(); const urlPrefix = orgBranding ? orgBranding?.fullDomain.replace(/^(https?:|)\/\//, "") : `${WEBSITE_URL?.replace(/^(https?:|)\/\//, "")}`; - return ; + return ( + + ); }; export default EventSetupTabWebWrapper; diff --git a/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabPlatformWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabPlatformWrapper.tsx index be3ead1f4d..887cb6f6fc 100644 --- a/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabPlatformWrapper.tsx +++ b/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabPlatformWrapper.tsx @@ -3,8 +3,11 @@ import { type EventTeamAssignmentTabBaseProps, } from "@calcom/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab"; -const EventTeamAssignmentTabPlatformWrapper = (props: EventTeamAssignmentTabBaseProps) => { - return ; +const EventTeamAssignmentTabPlatformWrapper = ( + props: Omit +) => { + // todo: implement attributes for platform orgs for segment + return ; }; export default EventTeamAssignmentTabPlatformWrapper; diff --git a/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabWebWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabWebWrapper.tsx index 0e9f234677..5ce33984fb 100644 --- a/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabWebWrapper.tsx +++ b/packages/platform/atoms/event-types/wrappers/EventTeamAssignmentTabWebWrapper.tsx @@ -3,8 +3,11 @@ import { type EventTeamAssignmentTabBaseProps, } from "@calcom/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab"; -const EventTeamAssignmentTabWebWrapper = (props: EventTeamAssignmentTabBaseProps) => { - return ; +const EventTeamAssignmentTabWebWrapper = ( + props: Omit +) => { + const isSegmentApplicable = !!props.orgId; + return ; }; export default EventTeamAssignmentTabWebWrapper; diff --git a/packages/platform/atoms/monorepo.ts b/packages/platform/atoms/monorepo.ts index 86cc52e728..fae9470223 100644 --- a/packages/platform/atoms/monorepo.ts +++ b/packages/platform/atoms/monorepo.ts @@ -12,3 +12,5 @@ export * from "./availability"; export { EventTypeWebWrapper as EventType } from "./event-types/wrappers/EventTypeWebWrapper"; export type { UpdateScheduleInput_2024_06_11 as UpdateScheduleBody } from "@calcom/platform-types"; export { Shell } from "./src/components/ui/shell"; +export { AddMembersWithSwitchWebWrapper } from "./add-members-switch/AddMembersWithSwitchWebWrapper"; +export { AddMembersWithSwitchPlatformWrapper } from "./add-members-switch/AddMembersWithSwitchPlatformWrapper"; diff --git a/packages/platform/atoms/package.json b/packages/platform/atoms/package.json index 636d67efa8..8a0a142c14 100644 --- a/packages/platform/atoms/package.json +++ b/packages/platform/atoms/package.json @@ -67,5 +67,10 @@ "tailwind-merge": "^1.13.2", "tailwindcss": "^3.3.3", "tailwindcss-animate": "^1.0.6" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-awesome-query-builder": "^5.1.2", + "react-dom": "^18.0.0 || ^19.0.0" } } diff --git a/packages/platform/atoms/vite.config.ts b/packages/platform/atoms/vite.config.ts index 4bf1fae9b6..5dbb34003d 100644 --- a/packages/platform/atoms/vite.config.ts +++ b/packages/platform/atoms/vite.config.ts @@ -37,7 +37,7 @@ export default defineConfig(({ mode }) => { fileName: "cal-atoms", }, rollupOptions: { - external: ["react", "fs", "path", "os", "react-dom"], + external: ["react", "fs", "path", "os", "react-dom", "react-awesome-query-builder"], output: { globals: { react: "React",