feat(activities): split customer column, wider search, custom activity types with type-specific fields

- Table: separate assignee and customer columns; search by assignee and activity type
- ActivityTypeDef model with per-type field definitions (text, select, checklist, participants, ...)
- Default types incl. meeting subject/participants and task checklist; admins manage types
- Participants see activities in their lists and get notified

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-07 12:29:23 +03:30
co-authored by Cursor
parent aa2f39256a
commit 13668c4ba4
17 changed files with 3371 additions and 147 deletions
+159
View File
@@ -1199,6 +1199,152 @@ export interface ActivityStageCountsDto {
total: number;
}
/** برچسب نوع پایه (برای گزارش‌ها و فعالیت‌های بدون نوع سفارشی) */
export const ACTIVITY_TYPE_LABELS: Record<ActivityType, string> = {
call: "تماس",
meeting: "جلسه",
task: "وظیفه",
note: "پیام",
};
export type ActivityFieldType =
| "text"
| "textarea"
| "number"
| "date"
| "url"
| "select"
| "multiselect"
| "checkbox"
| "checklist"
| "participants";
export const ACTIVITY_FIELD_TYPES: ActivityFieldType[] = [
"text",
"textarea",
"number",
"date",
"url",
"select",
"multiselect",
"checkbox",
"checklist",
"participants",
];
export const ACTIVITY_FIELD_TYPE_LABELS: Record<ActivityFieldType, string> = {
text: "متن کوتاه",
textarea: "متن بلند",
number: "عدد",
date: "تاریخ",
url: "لینک",
select: "انتخاب از لیست",
multiselect: "چندانتخابی",
checkbox: "بله / خیر",
checklist: "چک‌لیست (لیست کارها)",
participants: "شرکت‌کنندگان",
};
/** فیلدهایی که گزینه لازم دارند */
export const ACTIVITY_FIELD_TYPES_WITH_OPTIONS: ActivityFieldType[] = ["select", "multiselect"];
export interface ActivityFieldDef {
/** کلید پایدار (a-z، 0-9، _) — با تغییر برچسب عوض نمی‌شود */
key: string;
label: string;
type: ActivityFieldType;
options?: string[];
required?: boolean;
placeholder?: string | null;
}
export interface ActivityChecklistItem {
id: string;
text: string;
done: boolean;
}
export interface ActivityParticipantsValue {
/** کاربران سازمان — فعالیت در لیست آن‌ها هم دیده می‌شود */
userIds: string[];
/** اشخاص (مشتریان) */
people: Array<{ id: string; name: string }>;
/** مهمانان آزاد (نام) */
guests: string[];
}
export type ActivityFieldValue =
| string
| number
| boolean
| string[]
| ActivityChecklistItem[]
| ActivityParticipantsValue
| null;
export type ActivityFieldValues = Record<string, ActivityFieldValue>;
export const ACTIVITY_TYPE_ICONS = [
"phone",
"users",
"check",
"chat",
"mail",
"building",
"calendar",
"star",
"flag",
"briefcase",
"document",
"target",
"truck",
"send",
"megaphone",
"pin",
"bell",
"sparkle",
] as const;
export type ActivityTypeIcon = (typeof ACTIVITY_TYPE_ICONS)[number];
export interface ActivityTypeSummaryDto {
id: string;
name: string;
icon: ActivityTypeIcon;
color: ActivityStageColor;
}
export interface ActivityTypeDefDto extends ActivityTypeSummaryDto {
/** نوع پایه — مبنای گزارش‌ها و سازگاری */
baseType: ActivityType;
fields: ActivityFieldDef[];
position: number;
isActive: boolean;
/** چهار نوع اصلی — حذف‌شدنی نیستند */
isSystem: boolean;
}
export interface CreateActivityTypeRequest {
name: string;
baseType?: ActivityType;
icon?: ActivityTypeIcon;
color?: ActivityStageColor;
fields?: ActivityFieldDef[];
}
export interface UpdateActivityTypeRequest {
name?: string;
baseType?: ActivityType;
icon?: ActivityTypeIcon;
color?: ActivityStageColor;
fields?: ActivityFieldDef[];
isActive?: boolean;
}
export interface ReorderActivityTypesRequest {
typeIds: string[];
}
export type CustomFieldEntity = "person" | "company" | "deal";
export type CustomFieldType = "text" | "number" | "date" | "boolean" | "select";
@@ -1267,6 +1413,14 @@ export interface ActivityDto {
createdBy: UserSummaryDto | null;
/** مرحلهٔ مؤثر (ستون کانبان) */
stageId?: string | null;
/** نوع مؤثر (سفارشی یا نوع اصلیِ همان type) */
typeDef?: ActivityTypeSummaryDto | null;
/** مقادیر فیلدهای اختصاصی نوع */
fields?: ActivityFieldValues;
/** کاربران شرکت‌کننده (از فیلدهای شرکت‌کنندگان) */
participantIds?: string[];
/** نام کاربران شرکت‌کننده — فقط در جزئیات فعالیت */
participantUsers?: UserSummaryDto[];
createdAt: string;
updatedAt: string;
}
@@ -1276,6 +1430,9 @@ export interface CreateActivityRequest {
/** مرحلهٔ اولیه؛ وضعیت فعالیت از نوع مرحله گرفته می‌شود */
stageId?: string | null;
type?: ActivityType;
/** نوع سفارشی؛ type از نوع پایهٔ آن گرفته می‌شود */
typeDefId?: string | null;
fields?: ActivityFieldValues;
priority?: ActivityPriority;
description?: string;
dueAt?: string | null;
@@ -1296,6 +1453,8 @@ export interface CreateActivityRequest {
export interface UpdateActivityRequest {
title?: string;
type?: ActivityType;
typeDefId?: string | null;
fields?: ActivityFieldValues;
status?: ActivityStatus;
priority?: ActivityPriority;
description?: string | null;