"use client";
import type { FeatureState } from "@calcom/features/flags/config";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import classNames from "@calcom/ui/classNames";
import { Alert } from "@calcom/ui/components/alert";
import { SettingsToggle, ToggleGroup } from "@calcom/ui/components/form";
import { SkeletonText } from "@calcom/ui/components/skeleton";
import { CircleAlertIcon, CircleCheckIcon } from "@coss/ui/icons";
import { Tooltip } from "@calcom/ui/components/tooltip";
import type { ReactElement } from "react";
import { useMemo } from "react";
import { getOptInFeatureConfig } from "@calcom/features/feature-opt-in/config";
import type { NormalizedFeature, UseFeatureOptInResult } from "@calcom/features/feature-opt-in/types";
interface FeaturesSettingsProps {
/** The hook result - can be from useUserFeatureOptIn, useTeamFeatureOptIn, or useOrganizationFeatureOptIn */
featureOptIn: UseFeatureOptInResult;
/** Whether the user can edit the feature settings. If false, all toggles will be disabled. */
canEdit?: boolean;
}
interface ToggleOption {
value: string;
label: string;
}
function isEnabledViaAutoOptIn(feature: NormalizedFeature, autoOptIn: boolean): boolean {
return feature.currentState === "inherit" && autoOptIn && feature.globalEnabled;
}
function handleValueChange(
val: string | undefined,
slug: string,
setFeatureState: (slug: string, state: FeatureState) => void
): void {
if (!val) return;
setFeatureState(slug, val as FeatureState);
}
function LoadingSkeleton(): ReactElement {
return (
);
}
function EmptyState({ message }: { message: string }): ReactElement {
return ;
}
function FeatureItem({
feature,
toggleOptions,
getBlockedWarning,
isBlockedByHigherLevel,
autoOptIn,
setFeatureState,
canEdit,
t,
}: {
feature: NormalizedFeature;
toggleOptions: ToggleOption[];
getBlockedWarning: (feature: NormalizedFeature) => string | null;
isBlockedByHigherLevel: (feature: NormalizedFeature) => boolean;
autoOptIn: boolean;
setFeatureState: (slug: string, state: FeatureState) => void;
canEdit: boolean;
t: (key: string) => string;
}): ReactElement | null {
const config = getOptInFeatureConfig(feature.slug);
const blockedWarning = getBlockedWarning(feature);
const enabledViaAutoOptInFlag = isEnabledViaAutoOptIn(feature, autoOptIn);
const blockedByHigherLevel = isBlockedByHigherLevel(feature);
const isDisabled = blockedByHigherLevel || !canEdit;
const finalToggleOptions = useMemo(() => {
if (!isDisabled) {
return toggleOptions;
}
return toggleOptions.map((option) => ({
...option,
disabled: true,
}));
}, [toggleOptions, isDisabled]);
if (!config) return null;
return (
{t(config.i18n.name)}
{blockedWarning && (
)}
{enabledViaAutoOptInFlag && (
)}
{t(config.i18n.description)}
handleValueChange(val, feature.slug, setFeatureState)
}
options={finalToggleOptions}
/>
);
}
export function FeaturesSettings({ featureOptIn, canEdit = true }: FeaturesSettingsProps): ReactElement {
const { t } = useLocale();
const {
features,
autoOptIn,
isLoading,
setFeatureState,
setAutoOptIn,
isAutoOptInMutationPending,
toggleLabels,
autoOptInDescription,
getBlockedWarning,
isBlockedByHigherLevel,
} = featureOptIn;
if (isLoading) return ;
const toggleOptions: ToggleOption[] = [
{ value: "disabled", label: toggleLabels.disabled },
{ value: "enabled", label: toggleLabels.enabled },
{ value: "inherit", label: toggleLabels.inherit },
];
return (
<>
{features.length === 0 &&
}
{features.length > 0 && (
{features.map((feature) => (
))}
)}
>
);
}
export default FeaturesSettings;