feat(leads): keep gender on leads and form submissions
A lead can carry the same honorific as a person, and a form that asks gender writes it onto the lead. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
MaxLength,
|
||||
MinLength,
|
||||
} from 'class-validator';
|
||||
import { PERSON_GENDERS } from '@mento/shared';
|
||||
|
||||
export class LeadSmsDto {
|
||||
@IsString()
|
||||
@@ -26,6 +27,8 @@ export class CreateLeadDto {
|
||||
mobile!: string;
|
||||
|
||||
@IsOptional() @IsString() contactName?: string;
|
||||
@IsOptional() @IsIn(PERSON_GENDERS) gender?: (typeof PERSON_GENDERS)[number];
|
||||
@IsOptional() @IsBoolean() showGenderInName?: boolean;
|
||||
@IsOptional() @IsString() phone?: string;
|
||||
@IsOptional() @IsString() city?: string;
|
||||
@IsOptional() @IsString() region?: string;
|
||||
@@ -47,6 +50,8 @@ export class UpdateLeadDto {
|
||||
@IsOptional() @IsString() @MinLength(1) title?: string;
|
||||
@IsOptional() @IsString() @MinLength(5) mobile?: string;
|
||||
@IsOptional() @IsString() contactName?: string | null;
|
||||
@IsOptional() @IsIn(PERSON_GENDERS) gender?: (typeof PERSON_GENDERS)[number];
|
||||
@IsOptional() @IsBoolean() showGenderInName?: boolean;
|
||||
@IsOptional() @IsString() phone?: string | null;
|
||||
@IsOptional() @IsString() city?: string | null;
|
||||
@IsOptional() @IsString() region?: string | null;
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
PaginatedResponse,
|
||||
} from '@mento/shared';
|
||||
import { FILTERED_IDS_MAX } from '@mento/shared';
|
||||
import { applyLeadGenderName, applyPersonGenderTitle } from '@mento/shared';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { SmsGatewayService } from '../sms-billing/sms-gateway.service';
|
||||
import { renderSmsText } from '../common/sms-text';
|
||||
@@ -341,6 +342,8 @@ export class LeadsService {
|
||||
title: string;
|
||||
mobile: string;
|
||||
contactName?: string | null;
|
||||
gender?: string | null;
|
||||
showGenderInName?: boolean | null;
|
||||
phone?: string | null;
|
||||
city?: string | null;
|
||||
region?: string | null;
|
||||
@@ -382,11 +385,22 @@ export class LeadsService {
|
||||
}
|
||||
|
||||
const registeredAt = dto.registeredAt ? new Date(dto.registeredAt) : null;
|
||||
const named = applyLeadGenderName({
|
||||
title: dto.title,
|
||||
contactName: dto.contactName,
|
||||
gender:
|
||||
dto.gender === 'male' || dto.gender === 'female' || dto.gender === 'none'
|
||||
? dto.gender
|
||||
: undefined,
|
||||
showGenderInName: dto.showGenderInName,
|
||||
});
|
||||
const row = await this.prisma.lead.create({
|
||||
data: {
|
||||
organizationId: actor.organizationId,
|
||||
title: dto.title.trim(),
|
||||
contactName: emptyToNull(dto.contactName),
|
||||
title: named.title,
|
||||
contactName: named.contactName,
|
||||
gender: named.gender,
|
||||
showGenderInName: named.showGenderInName,
|
||||
mobile,
|
||||
phone: emptyToNull(dto.phone),
|
||||
city: emptyToNull(dto.city),
|
||||
@@ -461,12 +475,41 @@ export class LeadsService {
|
||||
}
|
||||
}
|
||||
|
||||
const touchName =
|
||||
typeof dto.title === 'string' ||
|
||||
dto.contactName !== undefined ||
|
||||
dto.gender !== undefined ||
|
||||
dto.showGenderInName !== undefined;
|
||||
const named = touchName
|
||||
? applyLeadGenderName({
|
||||
title: typeof dto.title === 'string' ? dto.title : existing.title,
|
||||
contactName:
|
||||
dto.contactName !== undefined
|
||||
? (dto.contactName as string | null)
|
||||
: existing.contactName,
|
||||
gender:
|
||||
dto.gender === 'male' || dto.gender === 'female' || dto.gender === 'none'
|
||||
? dto.gender
|
||||
: existing.gender === 'male' || existing.gender === 'female'
|
||||
? existing.gender
|
||||
: 'none',
|
||||
showGenderInName:
|
||||
typeof dto.showGenderInName === 'boolean'
|
||||
? dto.showGenderInName
|
||||
: existing.showGenderInName,
|
||||
})
|
||||
: null;
|
||||
|
||||
const data: Prisma.LeadUpdateInput = {
|
||||
...(typeof dto.title === 'string' ? { title: dto.title.trim() } : {}),
|
||||
mobile,
|
||||
...(dto.contactName !== undefined
|
||||
? { contactName: emptyToNull(dto.contactName as string) }
|
||||
...(named
|
||||
? {
|
||||
title: named.title,
|
||||
contactName: named.contactName,
|
||||
gender: named.gender,
|
||||
showGenderInName: named.showGenderInName,
|
||||
}
|
||||
: {}),
|
||||
mobile,
|
||||
...(dto.phone !== undefined
|
||||
? { phone: emptyToNull(dto.phone as string) }
|
||||
: {}),
|
||||
@@ -877,13 +920,24 @@ export class LeadsService {
|
||||
? `${dto.firstName ?? ''} ${dto.lastName ?? ''}`.trim()
|
||||
: (lead.contactName || lead.title).trim();
|
||||
const nameParts = rawName.split(/\s+/).filter(Boolean);
|
||||
const firstName = nameParts[0] || lead.title;
|
||||
const lastName = nameParts.slice(1).join(' ') || '—';
|
||||
const bareFirst = nameParts[0] || lead.title;
|
||||
const bareLast = nameParts.slice(1).join(' ');
|
||||
const named = applyPersonGenderTitle({
|
||||
firstName: bareFirst,
|
||||
lastName: bareLast,
|
||||
gender:
|
||||
lead.gender === 'male' || lead.gender === 'female' || lead.gender === 'none'
|
||||
? lead.gender
|
||||
: 'none',
|
||||
showGenderInName: lead.showGenderInName,
|
||||
});
|
||||
person = await this.prisma.person.create({
|
||||
data: {
|
||||
organizationId: actor.organizationId,
|
||||
firstName,
|
||||
lastName,
|
||||
firstName: named.firstName,
|
||||
lastName: named.lastName,
|
||||
gender: named.gender,
|
||||
showGenderInName: named.showGenderInName,
|
||||
mobile: lead.mobile,
|
||||
phone: lead.phone,
|
||||
instagram: lead.instagram,
|
||||
@@ -1202,6 +1256,8 @@ export class LeadsService {
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
contactName: row.contactName,
|
||||
gender: row.gender === 'male' || row.gender === 'female' ? row.gender : 'none',
|
||||
showGenderInName: row.showGenderInName,
|
||||
mobile: row.mobile,
|
||||
phone: row.phone,
|
||||
city: row.city,
|
||||
|
||||
Reference in New Issue
Block a user