Files
calendar/packages/features/attributes/services/AttributeService.ts
T
98b6d63164 refactor: apply biome formatting to packages/features (#27844)
* refactor: apply biome formatting to packages/features (batch 1 - small subdirs)

Format small subdirectories in packages/features: di, flags, holidays, oauth,
settings, users, assignment-reason, selectedCalendar, hashedLink, host, form,
form-builder, availability, data-table, pbac, schedules, troubleshooter,
eventtypes, calendar-subscription, and root-level files.

Also includes straggler apps/web BookEventForm.tsx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: apply biome formatting to packages/features (batch 2 - medium subdirs)

Format medium subdirectories in packages/features: auth, credentials,
calendars, routing-forms, routing-trace, attributes, watchlist, calAIPhone,
tasker, and webhooks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: apply biome formatting to packages/features (batch 3 - bookings + insights)

Format bookings and insights subdirectories in packages/features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: apply biome formatting to packages/features (batch 4 - ee)

Format packages/features/ee subdirectory covering billing, workflows,
organizations, teams, managed-event-types, round-robin, dsync,
integration-attribute-sync, and payments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: apply biome formatting to packages/features (batch 5 - booking-audit part 1)

Format booking-audit di, actions, common, dto, repository, and types
subdirectories in packages/features/booking-audit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: apply biome formatting to packages/features (batch 6 - booking-audit part 2)

Format booking-audit service subdirectory in packages/features/booking-audit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 15:47:14 +01:00

70 lines
2.2 KiB
TypeScript

import type { PrismaAttributeToUserRepository } from "@calcom/features/attributes/repositories/PrismaAttributeToUserRepository";
import { AttributeType } from "@calcom/prisma/enums";
interface IAttributeServiceDeps {
attributeToUserRepository: PrismaAttributeToUserRepository;
}
type MultiSelectAttribute = {
type: "MULTI_SELECT";
optionIds: Set<string>;
values: Set<string>;
};
type SingleValueAttribute = {
type: "TEXT" | "NUMBER" | "SINGLE_SELECT";
optionId: string | null;
value: string | null;
};
export type UserAttribute = MultiSelectAttribute | SingleValueAttribute;
export class AttributeService {
constructor(private readonly deps: IAttributeServiceDeps) {}
/** Grouped by attribute */
async getUsersAttributesByOrgMembershipId({
userId,
orgId,
}: {
userId: number;
orgId: number;
}): Promise<Record<string, UserAttribute>> {
const attributeOptionsAssignedToUser = await this.deps.attributeToUserRepository.findManyIncludeAttribute(
{
member: { userId, teamId: orgId },
}
);
const userAttributes: Record<string, UserAttribute> = {};
for (const assignedAttribute of attributeOptionsAssignedToUser) {
const attribute = assignedAttribute.attributeOption.attribute;
const attributeOptionId = assignedAttribute.attributeOptionId;
const attributeValue = assignedAttribute.attributeOption.value;
if (attribute.type === AttributeType.MULTI_SELECT) {
if (attribute.id in userAttributes) {
const existing = userAttributes[attribute.id] as MultiSelectAttribute;
existing.optionIds.add(attributeOptionId);
existing.values.add(attributeValue);
} else {
userAttributes[attribute.id] = {
type: "MULTI_SELECT",
optionIds: new Set([attributeOptionId]),
values: new Set([attributeValue]),
};
}
} else {
// For TEXT, NUMBER, SINGLE_SELECT - only store single value
userAttributes[attribute.id] = {
type: attribute.type as "TEXT" | "NUMBER" | "SINGLE_SELECT",
optionId: attributeOptionId,
value: attributeValue,
};
}
}
return userAttributes;
}
}