Skip to content

Commit 41bdabd

Browse files
committed
refactor(contact): Implement phone number formatting for contact details in PDF
1 parent 83bf7b2 commit 41bdabd

3 files changed

Lines changed: 132 additions & 16 deletions

File tree

src/components/pdf/FieldCompilationNotesPdf.tsx

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import {
1414
buildPdfFilename,
1515
formatAddress,
1616
formatAppDate,
17-
formatPhone,
1817
sanitizeContacts,
1918
} from '@/utils'
2019
import { usePrimaryAndSecondaryContact } from '@/hooks'
20+
import { formatContactPhones } from './fieldCompilationPhoneFormatter'
2121

2222
const styles = StyleSheet.create({
2323
page: {
@@ -409,11 +409,6 @@ const locationNotesText = (well: IWell) =>
409409

410410
const contactEmail = (contact?: IContact) => contact?.emails?.[0]?.email ?? '-'
411411

412-
const contactPhone = (contact?: IContact) => {
413-
const phone = contact?.phones?.[0]?.phone_number ?? null
414-
return phone ? formatPhone(phone) : '-'
415-
}
416-
417412
const contactAddress = (contact?: IContact) => {
418413
const address = contact?.addresses?.[0]
419414
return address ? formatAddress(address) : '-'
@@ -698,16 +693,31 @@ const FieldCompilationNotesPage = ({
698693
</Text>
699694
</View>
700695
</View>
701-
<View style={styles.contactDetails}>
702-
<Text style={styles.line}>{contactAddress(primaryContact)}</Text>
703-
<Text style={styles.line}>
704-
<Text style={styles.label}>Phone: </Text>
705-
{contactPhone(primaryContact)}
706-
</Text>
707-
<Text style={styles.line}>
708-
<Text style={styles.label}>Email: </Text>
709-
{contactEmail(primaryContact)}
710-
</Text>
696+
<View style={styles.contactsRow}>
697+
<View style={[styles.contactColumn, styles.contactDetails]}>
698+
<Text style={styles.line}>{contactAddress(primaryContact)}</Text>
699+
<Text style={styles.line}>
700+
<Text style={styles.label}>Phone: </Text>
701+
{formatContactPhones(primaryContact)}
702+
</Text>
703+
<Text style={styles.line}>
704+
<Text style={styles.label}>Email: </Text>
705+
{contactEmail(primaryContact)}
706+
</Text>
707+
</View>
708+
<View style={[styles.contactColumn, styles.contactDetails]}>
709+
<Text style={styles.line}>
710+
{contactAddress(secondaryContact)}
711+
</Text>
712+
<Text style={styles.line}>
713+
<Text style={styles.label}>Phone: </Text>
714+
{formatContactPhones(secondaryContact)}
715+
</Text>
716+
<Text style={styles.line}>
717+
<Text style={styles.label}>Email: </Text>
718+
{contactEmail(secondaryContact)}
719+
</Text>
720+
</View>
711721
</View>
712722
</View>
713723

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { IContact } from '@/interfaces/ocotillo'
2+
import { formatPhone } from '@/utils/FormatPhone'
3+
4+
export const formatContactPhones = (contact?: IContact) => {
5+
const values =
6+
contact?.phones
7+
?.map((phone) => {
8+
const rawPhone = phone?.phone_number?.trim()
9+
if (!rawPhone) return null
10+
11+
const formattedPhone = formatPhone(rawPhone)
12+
return phone.phone_type
13+
? `${phone.phone_type}: ${formattedPhone}`
14+
: formattedPhone
15+
})
16+
.filter((value): value is string => Boolean(value)) ?? []
17+
18+
return values.length > 0 ? values.join('\n') : '-'
19+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { describe, expect, it } from 'vitest'
2+
import type { IContact } from '@/interfaces/ocotillo'
3+
import { formatContactPhones } from '@/components/pdf/fieldCompilationPhoneFormatter'
4+
5+
const makeContact = (
6+
phones: NonNullable<IContact['phones']>
7+
): IContact =>
8+
({
9+
id: 1,
10+
name: 'Test Contact',
11+
created_at: new Date('2026-01-01T00:00:00Z'),
12+
release_status: 'public',
13+
phones,
14+
}) as IContact
15+
16+
describe('formatContactPhones', () => {
17+
it('formats a single phone number with its type', () => {
18+
const contact = makeContact([
19+
{
20+
id: 1,
21+
created_at: new Date('2026-01-01T00:00:00Z'),
22+
release_status: 'public',
23+
contact_id: 1,
24+
phone_number: '5053300761',
25+
phone_type: 'Primary',
26+
},
27+
])
28+
29+
expect(formatContactPhones(contact)).toBe('Primary: (505) 330-0761')
30+
})
31+
32+
it('includes all phone numbers in stored order on separate lines', () => {
33+
const contact = makeContact([
34+
{
35+
id: 1,
36+
created_at: new Date('2026-01-01T00:00:00Z'),
37+
release_status: 'public',
38+
contact_id: 1,
39+
phone_number: '5053300761',
40+
phone_type: 'Work',
41+
},
42+
{
43+
id: 2,
44+
created_at: new Date('2026-01-01T00:00:00Z'),
45+
release_status: 'public',
46+
contact_id: 1,
47+
phone_number: '15755551212',
48+
phone_type: 'Mobile',
49+
},
50+
])
51+
52+
expect(formatContactPhones(contact)).toBe(
53+
'Work: (505) 330-0761\nMobile: +1 (575) 555-1212'
54+
)
55+
})
56+
57+
it('renders unlabeled numbers without a type prefix', () => {
58+
const contact = makeContact([
59+
{
60+
id: 1,
61+
created_at: new Date('2026-01-01T00:00:00Z'),
62+
release_status: 'public',
63+
contact_id: 1,
64+
phone_number: '5053300761',
65+
phone_type: '',
66+
},
67+
])
68+
69+
expect(formatContactPhones(contact)).toBe('(505) 330-0761')
70+
})
71+
72+
it('ignores empty numbers and falls back to dash when none remain', () => {
73+
const contact = makeContact([
74+
{
75+
id: 1,
76+
created_at: new Date('2026-01-01T00:00:00Z'),
77+
release_status: 'public',
78+
contact_id: 1,
79+
phone_number: ' ',
80+
phone_type: 'Primary',
81+
},
82+
])
83+
84+
expect(formatContactPhones(contact)).toBe('-')
85+
expect(formatContactPhones(undefined)).toBe('-')
86+
})
87+
})

0 commit comments

Comments
 (0)