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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 39x 7x 7x 1x 6x 6x 19x 19x 1x 18x 1x 17x 1x 16x 6x 6x 2x 14x 1x 13x 1x 12x 2x 12x 12x 84x 6x 12x 12x 12x 12x 12x 12x 2x 12x 2x 12x 12x 12x 12x 12x 4x 12x 3x 12x 12x 12x 3x 12x 3x 12x 12x 12x 12x 1x 11x | // Profile Service - Core company profile CRUD operations
import type { Dal } from "../../dal";
import type { Pro } from "../../db/schema";
import type { UpdateProfileInput, CompanyProfileResponse } from "./types";
import { NotFoundError, ValidationError } from "../../lib/errors";
export class ProfileService {
constructor(private dal: Dal) {}
async getCompanyProfile(proId: string): Promise<CompanyProfileResponse> {
const pro = await this.dal.pros.findById(proId);
if (!pro) {
throw new NotFoundError("Pro not found");
}
const [leadership, certifications, testimonials] = await Promise.all([
this.dal.companyProfile.getLeadership(proId),
this.dal.companyProfile.getCertifications(proId),
this.dal.companyProfile.getTestimonials(proId),
]);
return {
tagline: pro.tagline ?? null,
about: pro.about ?? null,
establishedYear: pro.establishedYear ?? null,
teamSizeCategory: pro.teamSize ?? null,
areasServed: pro.serviceAreaIds ?? null,
processDescription: pro.processDescription ?? null,
socialLinks: {
instagramHandle: pro.instagramHandle ?? null,
facebookUrl: pro.facebookUrl ?? null,
youtubeUrl: pro.youtubeUrl ?? null,
googleBusinessUrl: pro.googleBusinessUrl ?? null,
websiteUrl: pro.websiteUrl ?? null,
linkedinUrl: pro.linkedinUrl ?? null,
twitterUrl: pro.twitterUrl ?? null,
pinterestUrl: pro.pinterestUrl ?? null,
},
leadershipTeam: leadership,
certifications,
testimonials,
};
}
async updateProfile(
proId: string,
data: UpdateProfileInput,
): Promise<Pro> {
const pro = await this.dal.pros.findById(proId);
if (!pro) {
throw new NotFoundError("Pro not found");
}
// Validate fields
if (data.tagline && data.tagline.length > 120) {
throw new ValidationError("Tagline must be 120 characters or less");
}
if (data.about && data.about.length > 1000) {
throw new ValidationError("About must be 1000 characters or less");
}
if (data.establishedYear) {
const currentYear = new Date().getFullYear();
if (data.establishedYear < 1950 || data.establishedYear > currentYear) {
throw new ValidationError("Please enter a valid year");
}
}
if (data.areasServed && data.areasServed.length > 10) {
throw new ValidationError("You can add up to 10 areas");
}
if (data.processDescription && data.processDescription.length > 500) {
throw new ValidationError(
"Process description must be 500 characters or less",
);
}
// Clean Instagram handle (remove @ if present)
if (data.instagramHandle) {
data.instagramHandle = data.instagramHandle.replace(/^@/, "");
}
// Ensure URLs have protocol
const urlFields = [
"facebookUrl",
"youtubeUrl",
"googleBusinessUrl",
"websiteUrl",
"linkedinUrl",
"twitterUrl",
"pinterestUrl",
] as const;
for (const field of urlFields) {
if (data[field] && !data[field]?.startsWith("http")) {
data[field] = `https://${data[field]}`;
}
}
// Map UpdateProfileInput fields to pro column names
const proUpdate: Record<string, unknown> = {};
if (data.tagline !== undefined) proUpdate.tagline = data.tagline;
if (data.about !== undefined) proUpdate.about = data.about;
if (data.establishedYear !== undefined)
proUpdate.establishedYear = data.establishedYear;
if (data.teamSizeCategory !== undefined)
proUpdate.teamSize = data.teamSizeCategory;
if (data.areasServed !== undefined)
proUpdate.serviceAreaIds = data.areasServed;
if (data.processDescription !== undefined)
proUpdate.processDescription = data.processDescription;
if (data.instagramHandle !== undefined)
proUpdate.instagramHandle = data.instagramHandle;
if (data.facebookUrl !== undefined)
proUpdate.facebookUrl = data.facebookUrl;
if (data.youtubeUrl !== undefined)
proUpdate.youtubeUrl = data.youtubeUrl;
if (data.googleBusinessUrl !== undefined)
proUpdate.googleBusinessUrl = data.googleBusinessUrl;
if (data.websiteUrl !== undefined)
proUpdate.websiteUrl = data.websiteUrl;
if (data.linkedinUrl !== undefined)
proUpdate.linkedinUrl = data.linkedinUrl;
Iif (data.twitterUrl !== undefined) proUpdate.twitterUrl = data.twitterUrl;
Iif (data.pinterestUrl !== undefined)
proUpdate.pinterestUrl = data.pinterestUrl;
const updated = await this.dal.pros.update(proId, proUpdate);
if (!updated) {
throw new NotFoundError("Pro not found");
}
return updated;
}
}
|