* fix: use FeatureOptInService for bookings-v3 check * refactor: simplify FeatureOptInService API and fix bookings page - Add resolveFeatureStates method that takes only userId and featureIds - Update listFeaturesForUser to take only userId parameter - Remove getUserOrgAndTeamIds from _router.ts (now internal to service) - Fix bookings page to use new resolveFeatureStates method - Parallelize getUserFeaturesStatus and resolveFeatureStates calls Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * check session?.user?.id first * remove comment --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
100 lines
2.7 KiB
TypeScript
100 lines
2.7 KiB
TypeScript
import type { FeatureId, FeatureState } from "@calcom/features/flags/config";
|
|
|
|
import type { EffectiveStateReason } from "../lib/computeEffectiveState";
|
|
import type { OptInFeatureScope } from "../types";
|
|
|
|
export type { EffectiveStateReason };
|
|
|
|
export type UserRoleContext = {
|
|
isOrgAdmin: boolean;
|
|
orgId: number | null;
|
|
adminTeamIds: number[];
|
|
adminTeamNames: { id: number; name: string }[];
|
|
};
|
|
|
|
export type FeatureOptInEligibilityResult =
|
|
| {
|
|
status: "invalid_feature";
|
|
canOptIn: false;
|
|
userRoleContext: null;
|
|
blockingReason: null;
|
|
}
|
|
| {
|
|
status: "feature_disabled";
|
|
canOptIn: false;
|
|
userRoleContext: null;
|
|
blockingReason: string;
|
|
}
|
|
| {
|
|
status: "already_enabled";
|
|
canOptIn: false;
|
|
userRoleContext: null;
|
|
blockingReason: null;
|
|
}
|
|
| {
|
|
status: "blocked";
|
|
canOptIn: false;
|
|
userRoleContext: UserRoleContext;
|
|
blockingReason: string;
|
|
}
|
|
| {
|
|
status: "can_opt_in";
|
|
canOptIn: true;
|
|
userRoleContext: UserRoleContext;
|
|
blockingReason: null;
|
|
};
|
|
|
|
export type ResolvedFeatureState = {
|
|
featureId: FeatureId;
|
|
globalEnabled: boolean;
|
|
orgState: FeatureState;
|
|
teamStates: FeatureState[];
|
|
userState: FeatureState | undefined;
|
|
effectiveEnabled: boolean;
|
|
effectiveReason: EffectiveStateReason;
|
|
orgAutoOptIn: boolean;
|
|
teamAutoOptIns: boolean[];
|
|
userAutoOptIn: boolean;
|
|
};
|
|
|
|
export interface IFeatureOptInService {
|
|
resolveFeatureStatesAcrossTeams(input: {
|
|
userId: number;
|
|
orgId: number | null;
|
|
teamIds: number[];
|
|
featureIds: FeatureId[];
|
|
}): Promise<Record<string, ResolvedFeatureState>>;
|
|
resolveFeatureStates(input: {
|
|
userId: number;
|
|
featureIds: FeatureId[];
|
|
}): Promise<Record<string, ResolvedFeatureState>>;
|
|
listFeaturesForUser(input: { userId: number }): Promise<ResolvedFeatureState[]>;
|
|
listFeaturesForTeam(input: {
|
|
teamId: number;
|
|
parentOrgId?: number | null;
|
|
scope?: OptInFeatureScope;
|
|
}): Promise<
|
|
{ featureId: FeatureId; globalEnabled: boolean; teamState: FeatureState; orgState: FeatureState }[]
|
|
>;
|
|
setUserFeatureState(
|
|
input:
|
|
| { userId: number; featureId: FeatureId; state: "enabled" | "disabled"; assignedBy: number }
|
|
| { userId: number; featureId: FeatureId; state: "inherit" }
|
|
): Promise<void>;
|
|
setTeamFeatureState(
|
|
input:
|
|
| {
|
|
teamId: number;
|
|
featureId: FeatureId;
|
|
state: "enabled" | "disabled";
|
|
assignedBy: number;
|
|
scope?: OptInFeatureScope;
|
|
}
|
|
| { teamId: number; featureId: FeatureId; state: "inherit"; scope?: OptInFeatureScope }
|
|
): Promise<void>;
|
|
checkFeatureOptInEligibility(input: {
|
|
userId: number;
|
|
featureId: string;
|
|
}): Promise<FeatureOptInEligibilityResult>;
|
|
}
|