import { Type } from 'class-transformer'; import { Allow, IsArray, IsBoolean, IsDateString, IsIn, IsInt, IsObject, IsOptional, IsString, Max, MaxLength, Min, MinLength, ValidateIf, } from 'class-validator'; import type { ActivityFieldDef, ActivityFieldValues, ActivityTypeIcon } from '@mento/shared'; import { ACTIVITY_TYPE_ICONS } from '@mento/shared'; /** تکه‌های JSON از ایمپورت مرورگرگرا */ export class ImportActivityRowsDto { @IsArray() @Allow() rows!: Array>; @Type(() => Number) @IsInt() @Min(0) offset!: number; @Type(() => Number) @IsInt() @Min(0) total!: number; @IsOptional() @IsString() sessionId?: string; } const ACTIVITY_TYPES = ['call', 'meeting', 'task', 'note'] as const; const ACTIVITY_STATUSES = ['open', 'done', 'canceled'] as const; const ACTIVITY_PRIORITIES = ['very_low', 'low', 'medium', 'high', 'very_high'] as const; const ACTIVITY_FILTERS = ['today', 'overdue', 'upcoming', 'done', 'all'] as const; export class ListActivitiesQueryDto { @IsOptional() @IsIn(ACTIVITY_FILTERS) filter?: (typeof ACTIVITY_FILTERS)[number] = 'today'; @IsOptional() @IsString() q?: string; @IsOptional() @IsIn(['mine', 'team']) desk?: 'mine' | 'team'; @IsOptional() @IsIn(ACTIVITY_TYPES) type?: (typeof ACTIVITY_TYPES)[number]; @IsOptional() @IsIn(ACTIVITY_STATUSES) status?: (typeof ACTIVITY_STATUSES)[number]; @IsOptional() @IsString() assigneeId?: string; /** نوع فعالیت (تعریف‌شده در سازمان) */ @IsOptional() @IsString() typeDefId?: string; /** شناسهٔ مرحله یا 'all' — حالت تب/کانبان مراحل */ @IsOptional() @IsString() stageId?: string; /** گروه فعالیت؛ خالی = همهٔ گروه‌ها (در شمارش ستون‌ها = گروه پیش‌فرض) */ @IsOptional() @IsString() boardId?: string; @IsOptional() @IsString() personId?: string; @IsOptional() @IsString() companyId?: string; @IsOptional() @IsString() dealId?: string; @IsOptional() @IsString() leadId?: string; /** Inclusive start (ISO). When set with/without filter, restricts dueAt. */ @IsOptional() @IsDateString() from?: string; /** Exclusive end (ISO). */ @IsOptional() @IsDateString() to?: string; @IsOptional() @Type(() => Number) @IsInt() @Min(1) page?: number = 1; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(200) limit?: number = 50; } const STAGE_COLORS = ['green', 'orange', 'purple', 'blue', 'rose', 'slate'] as const; export class CreateActivityBoardDto { @IsString() @MinLength(2) @MaxLength(80) name!: string; } export class UpdateActivityBoardDto { @IsOptional() @IsString() @MinLength(2) @MaxLength(80) name?: string; } export class ListActivityStagesQueryDto { @IsOptional() @IsString() boardId?: string; } export class CreateActivityStageDto { /** خالی = گروه پیش‌فرض */ @IsOptional() @IsString() boardId?: string; @IsString() @MinLength(1) @MaxLength(80) name!: string; @IsOptional() @IsIn(STAGE_COLORS) color?: (typeof STAGE_COLORS)[number]; @IsOptional() @IsIn(ACTIVITY_STATUSES) kind?: (typeof ACTIVITY_STATUSES)[number]; } export class UpdateActivityStageDto { @IsOptional() @IsString() @MinLength(1) @MaxLength(80) name?: string; @IsOptional() @IsIn(STAGE_COLORS) color?: (typeof STAGE_COLORS)[number]; @IsOptional() @IsIn(ACTIVITY_STATUSES) kind?: (typeof ACTIVITY_STATUSES)[number]; } export class ReorderActivityStagesDto { @IsArray() @IsString({ each: true }) stageIds!: string[]; } export class MoveActivityStageDto { @IsString() stageId!: string; } /** محتوای fields در سرویس بر اساس تعریف نوع اعتبارسنجی می‌شود */ export class CreateActivityTypeDto { @IsString() @MinLength(1) @MaxLength(60) name!: string; @IsOptional() @IsIn(ACTIVITY_TYPES) baseType?: (typeof ACTIVITY_TYPES)[number]; @IsOptional() @IsIn(ACTIVITY_TYPE_ICONS) icon?: ActivityTypeIcon; @IsOptional() @IsIn(STAGE_COLORS) color?: (typeof STAGE_COLORS)[number]; @IsOptional() @IsArray() @Allow() fields?: ActivityFieldDef[]; } export class UpdateActivityTypeDto { @IsOptional() @IsString() @MinLength(1) @MaxLength(60) name?: string; @IsOptional() @IsIn(ACTIVITY_TYPES) baseType?: (typeof ACTIVITY_TYPES)[number]; @IsOptional() @IsIn(ACTIVITY_TYPE_ICONS) icon?: ActivityTypeIcon; @IsOptional() @IsIn(STAGE_COLORS) color?: (typeof STAGE_COLORS)[number]; @IsOptional() @IsArray() @Allow() fields?: ActivityFieldDef[]; @IsOptional() @IsBoolean() isActive?: boolean; } export class ReorderActivityTypesDto { @IsArray() @IsString({ each: true }) typeIds!: string[]; } export class CreateActivityDto { @IsString() @MinLength(2) @MaxLength(200) title!: string; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() boardId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() stageId?: string | null; @IsOptional() @IsIn(ACTIVITY_TYPES) type?: (typeof ACTIVITY_TYPES)[number]; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() typeDefId?: string | null; @IsOptional() @IsObject() fields?: ActivityFieldValues; @IsOptional() @IsIn(ACTIVITY_PRIORITIES) priority?: (typeof ACTIVITY_PRIORITIES)[number]; @IsOptional() @IsString() @MaxLength(2000) description?: string; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() dueAt?: string | null; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(24 * 60) durationMinutes?: number | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() reminderAt?: string | null; @IsOptional() @IsBoolean() reminderNotifyApp?: boolean; @IsOptional() @IsBoolean() reminderNotifySms?: boolean; @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[]; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() personId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() companyId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() dealId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() assigneeId?: string | null; @IsOptional() @IsArray() @IsString({ each: true }) assigneeIds?: string[]; } export class UpdateActivityDto { @IsOptional() @IsString() @MinLength(2) @MaxLength(200) title?: string; /** null/خالی = گروه پیش‌فرض */ @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() boardId?: string | null; @IsOptional() @IsIn(ACTIVITY_TYPES) type?: (typeof ACTIVITY_TYPES)[number]; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() typeDefId?: string | null; @IsOptional() @IsObject() fields?: ActivityFieldValues; @IsOptional() @IsIn(ACTIVITY_STATUSES) status?: (typeof ACTIVITY_STATUSES)[number]; @IsOptional() @IsIn(ACTIVITY_PRIORITIES) priority?: (typeof ACTIVITY_PRIORITIES)[number]; @IsOptional() @IsString() @MaxLength(2000) description?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() dueAt?: string | null; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(24 * 60) durationMinutes?: number | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() reminderAt?: string | null; @IsOptional() @IsBoolean() reminderNotifyApp?: boolean; @IsOptional() @IsBoolean() reminderNotifySms?: boolean; @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[]; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() personId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() companyId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() dealId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() assigneeId?: string | null; @IsOptional() @IsArray() @IsString({ each: true }) assigneeIds?: string[]; }