All files / services/company-profile leadership.service.ts

100% Statements 33/33
100% Branches 40/40
100% Functions 4/4
100% Lines 33/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99              33x             8x 8x 1x       7x 7x 1x       6x 1x   5x 1x   4x 1x       3x   3x                       3x               8x 8x 2x       6x 1x   5x 1x   4x 1x     3x       3x 1x     2x             4x 4x 2x     2x      
// Leadership Service - Leadership team management
import type { Dal } from "../../dal";
import type { ProLeadership } from "../../db/schema";
import type { AddLeadershipInput, UpdateLeadershipInput } from "./types";
import { NotFoundError, ValidationError } from "../../lib/errors";
 
export class LeadershipService {
	constructor(private dal: Dal) {}
 
	async addLeadershipMember(
		proId: string,
		data: AddLeadershipInput,
	): Promise<ProLeadership> {
		// Verify pro exists
		const pro = await this.dal.pros.findById(proId);
		if (!pro) {
			throw new NotFoundError("Pro not found");
		}
 
		// Check max limit (5 members)
		const count = await this.dal.companyProfile.countLeadership(proId);
		if (count >= 5) {
			throw new ValidationError("You can add up to 5 team members");
		}
 
		// Validate fields
		if (!data.name || data.name.length > 100) {
			throw new ValidationError("Name is required (max 100 characters)");
		}
		if (!data.role || data.role.length > 50) {
			throw new ValidationError("Role is required (max 50 characters)");
		}
		if (data.bio && data.bio.length > 300) {
			throw new ValidationError("Bio must be 300 characters or less");
		}
 
		const maxOrder =
			await this.dal.companyProfile.getMaxLeadershipOrder(proId);
 
		const member = await this.dal.companyProfile.createLeadership({
			proId,
			name: data.name,
			role: data.role,
			bio: data.bio,
			photoUrl: data.photoUrl,
			linkedinUrl: data.linkedinUrl,
			instagramHandle: data.instagramHandle,
			videoUrl: data.videoUrl,
			displayOrder: maxOrder + 1,
		});
 
		return member;
	}
 
	async updateLeadershipMember(
		proId: string,
		memberId: number,
		data: UpdateLeadershipInput,
	): Promise<ProLeadership> {
		const member = await this.dal.companyProfile.getLeadershipById(memberId);
		if (!member || member.proId !== proId) {
			throw new NotFoundError("Team member not found");
		}
 
		// Validate fields
		if (data.name !== undefined && (!data.name || data.name.length > 100)) {
			throw new ValidationError("Name is required (max 100 characters)");
		}
		if (data.role !== undefined && (!data.role || data.role.length > 50)) {
			throw new ValidationError("Role is required (max 50 characters)");
		}
		if (data.bio && data.bio.length > 300) {
			throw new ValidationError("Bio must be 300 characters or less");
		}
 
		const updated = await this.dal.companyProfile.updateLeadership(
			memberId,
			data,
		);
		if (!updated) {
			throw new NotFoundError("Team member not found");
		}
 
		return updated;
	}
 
	async deleteLeadershipMember(
		proId: string,
		memberId: number,
	): Promise<void> {
		const member = await this.dal.companyProfile.getLeadershipById(memberId);
		if (!member || member.proId !== proId) {
			throw new NotFoundError("Team member not found");
		}
 
		await this.dal.companyProfile.deleteLeadership(memberId);
	}
}