import { IsBoolean, IsOptional, IsString, IsArray, IsInt, IsEnum, IsUrl, MaxLength, Min, Max, MinLength, IsNumber, IsUUID, ValidateNested, IsDateString, } from "class-validator"; import { Type } from "class-transformer"; import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { VerificationStatus, BookmarkStatus, ProfileViewSource, NetworkBookingRequestStatus, ReputationTier, } from "@micprotocol/shared-types"; // ─── Expertise Tag DTO ─────────────────────────────── export class ExpertiseTagDto { @ApiProperty({ example: "Fintech" }) @IsString() @MinLength(1) @MaxLength(100) name!: string; @ApiPropertyOptional({ example: "Technology" }) @IsOptional() @IsString() @MaxLength(100) category?: string; } // ─── Availability Window DTO ───────────────────────── export class AvailabilityWindowDto { @ApiProperty({ example: 1, description: "0=Sunday, 6=Saturday" }) @IsInt() @Min(0) @Max(6) dayOfWeek!: number; @ApiProperty({ example: 9 }) @IsInt() @Min(0) @Max(23) startHour!: number; @ApiProperty({ example: 17 }) @IsInt() @Min(0) @Max(23) endHour!: number; @ApiPropertyOptional({ example: "Africa/Nairobi" }) @IsOptional() @IsString() timezone?: string; } // ─── Visibility Settings DTO ───────────────────────── export class VisibilitySettingsDto { @ApiPropertyOptional({ default: false }) @IsOptional() @IsBoolean() showEmail?: boolean; @ApiPropertyOptional({ default: false }) @IsOptional() @IsBoolean() showPhone?: boolean; @ApiPropertyOptional({ default: true }) @IsOptional() @IsBoolean() showAppearances?: boolean; @ApiPropertyOptional({ default: true }) @IsOptional() @IsBoolean() showReliabilityScore?: boolean; } // ─── Create Guest Public Profile ───────────────────── export class CreateGuestPublicProfileDto { @ApiPropertyOptional({ example: "Fintech Founder | Nairobi" }) @IsOptional() @IsString() @MaxLength(255) headline?: string; @ApiPropertyOptional({ example: "Building payment infrastructure for informal economies..." }) @IsOptional() @IsString() @MaxLength(5000) fullBio?: string; @ApiPropertyOptional({ example: "Kenya" }) @IsOptional() @IsString() @MaxLength(100) country?: string; @ApiPropertyOptional({ example: "Nairobi" }) @IsOptional() @IsString() @MaxLength(100) city?: string; @ApiPropertyOptional({ example: ["English", "Swahili"] }) @IsOptional() @IsArray() @IsString({ each: true }) languages?: string[]; @ApiPropertyOptional({ example: "Africa/Nairobi" }) @IsOptional() @IsString() @MaxLength(100) timezone?: string; @ApiPropertyOptional({ example: "+254700123456" }) @IsOptional() @IsString() @MaxLength(20) phoneNumber?: string; @ApiPropertyOptional({ example: "+254700123456" }) @IsOptional() @IsString() @MaxLength(20) whatsappNumber?: string; @ApiPropertyOptional() @IsOptional() @IsUrl() avatarUrl?: string; @ApiPropertyOptional({ default: true }) @IsOptional() @IsBoolean() isPublic?: boolean; @ApiPropertyOptional({ type: VisibilitySettingsDto }) @IsOptional() @ValidateNested() @Type(() => VisibilitySettingsDto) visibilitySettings?: VisibilitySettingsDto; @ApiPropertyOptional({ type: [ExpertiseTagDto] }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => ExpertiseTagDto) expertiseTags?: ExpertiseTagDto[]; @ApiPropertyOptional({ type: [AvailabilityWindowDto] }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => AvailabilityWindowDto) availabilityWindows?: AvailabilityWindowDto[]; } // ─── Update Guest Public Profile ───────────────────── export class UpdateGuestPublicProfileDto extends CreateGuestPublicProfileDto {} // ─── Guest Network Search DTO ──────────────────────── export class GuestNetworkSearchDto { @ApiPropertyOptional({ example: "fintech climate" }) @IsOptional() @IsString() @MaxLength(500) query?: string; @ApiPropertyOptional({ example: "Kenya" }) @IsOptional() @IsString() country?: string; @ApiPropertyOptional({ example: ["Kenya", "Nigeria"] }) @IsOptional() @IsArray() @IsString({ each: true }) countries?: string[]; @ApiPropertyOptional({ example: ["Fintech", "Climate"] }) @IsOptional() @IsArray() @IsString({ each: true }) expertise?: string[]; @ApiPropertyOptional({ example: ["English", "Swahili"] }) @IsOptional() @IsArray() @IsString({ each: true }) languages?: string[]; @ApiPropertyOptional({ example: 70 }) @IsOptional() @IsNumber() @Min(0) @Max(100) minReliabilityScore?: number; @ApiPropertyOptional({ example: 2 }) @IsOptional() @IsInt() @Min(0) minAppearances?: number; @ApiPropertyOptional({ enum: VerificationStatus }) @IsOptional() @IsEnum(VerificationStatus) verificationStatus?: VerificationStatus; @ApiPropertyOptional({ enum: ReputationTier }) @IsOptional() @IsEnum(ReputationTier) tier?: ReputationTier; @ApiPropertyOptional({ example: 24 }) @IsOptional() @IsInt() @Min(1) maxResponseTimeHours?: number; @ApiPropertyOptional({ default: "relevance" }) @IsOptional() @IsString() sortBy?: string; @ApiPropertyOptional({ default: "desc" }) @IsOptional() @IsString() sortOrder?: string; @ApiPropertyOptional({ default: 1 }) @IsOptional() @IsInt() @Min(1) page?: number; @ApiPropertyOptional({ default: 20 }) @IsOptional() @IsInt() @Min(1) @Max(50) limit?: number; } // ─── Create Network Booking Request ────────────────── export class CreateNetworkBookingRequestDto { @ApiProperty() @IsUUID() toProfileId!: string; @ApiProperty() @IsUUID() fromPodcastId!: string; @ApiProperty({ example: "We'd love to have you on our podcast to discuss fintech in East Africa" }) @IsString() @MinLength(10) @MaxLength(2000) message!: string; @ApiPropertyOptional({ example: ["Mobile Money", "Payment Rails"] }) @IsOptional() @IsArray() @IsString({ each: true }) proposedTopics?: string[]; @ApiPropertyOptional() @IsOptional() @IsArray() @IsDateString({}, { each: true }) proposedDates?: string[]; } // ─── Respond to Booking Request ────────────────────── export class RespondToBookingRequestDto { @ApiProperty({ enum: ["accepted", "declined"] }) @IsEnum(NetworkBookingRequestStatus) status!: "accepted" | "declined"; } // ─── Create Network Bookmark ───────────────────────── export class CreateNetworkBookmarkDto { @ApiProperty() @IsUUID() guestProfileId!: string; @ApiProperty() @IsUUID() podcastId!: string; @ApiPropertyOptional({ example: "Great fit for our fintech series" }) @IsOptional() @IsString() @MaxLength(1000) notes?: string; } // ─── Update Network Bookmark ───────────────────────── export class UpdateNetworkBookmarkDto { @ApiPropertyOptional({ enum: BookmarkStatus }) @IsOptional() @IsEnum(BookmarkStatus) status?: BookmarkStatus; @ApiPropertyOptional() @IsOptional() @IsString() @MaxLength(1000) notes?: string; } // ─── Create Host Review ────────────────────────────── export class CreateHostReviewDto { @ApiProperty() @IsUUID() bookingRequestId!: string; @ApiProperty() @IsUUID() profileId!: string; @ApiProperty({ example: 5, minimum: 1, maximum: 5 }) @IsInt() @Min(1) @Max(5) contentRating!: number; @ApiProperty({ example: 5, minimum: 1, maximum: 5 }) @IsInt() @Min(1) @Max(5) prepQuality!: number; @ApiProperty({ example: 5, minimum: 1, maximum: 5 }) @IsInt() @Min(1) @Max(5) overallRating!: number; @ApiPropertyOptional({ example: "Excellent guest, very well prepared." }) @IsOptional() @IsString() @MaxLength(2000) comment?: string; } // ─── Track Profile View ────────────────────────────── export class TrackProfileViewDto { @ApiProperty() @IsUUID() profileId!: string; @ApiPropertyOptional() @IsOptional() @IsUUID() viewerPodcastId?: string; @ApiPropertyOptional({ enum: ProfileViewSource }) @IsOptional() @IsEnum(ProfileViewSource) source?: ProfileViewSource; }