feat(invoice): make the phone number on the PDF a clickable tel: link

Wraps the phone in a @react-pdf 'Link' with src='tel:+\u2026' just like the
existing email (mailto:) and website (https:) entries in the contact
footer. Display string keeps the human-readable formatting (spaces,
parens) while the underlying URL is normalized per RFC 3966 (digits
plus an optional leading '+').

PDF readers on macOS, iOS, Android and most desktop Linux setups
launch the system dialer or a VoIP app on click; readers without a
'tel' handler fall back to selecting the number.
This commit is contained in:
Gerhard Scheikl
2026-05-15 16:20:55 +02:00
parent d5bdc41e0a
commit fe54f6e64a
+20 -1
View File
@@ -588,7 +588,11 @@ function Footer({ issuer, language }: { issuer: IssuerData; language: InvoiceLan
</View> </View>
<View style={styles.footerCol}> <View style={styles.footerCol}>
<Text style={styles.footerHeading}>{t.contactHeading}</Text> <Text style={styles.footerHeading}>{t.contactHeading}</Text>
{issuer.phone ? <Text>{t.phoneLabel}: {issuer.phone}</Text> : null} {issuer.phone ? (
<Text>
{t.phoneLabel}: <Link src={toTelUrl(issuer.phone)}>{issuer.phone}</Link>
</Text>
) : null}
{issuer.email ? ( {issuer.email ? (
<Text> <Text>
{t.emailLabel}: <Link src={`mailto:${issuer.email}`}>{issuer.email}</Link> {t.emailLabel}: <Link src={`mailto:${issuer.email}`}>{issuer.email}</Link>
@@ -644,6 +648,21 @@ function normaliseWebUrl(url: string): string {
return `https://${trimmed.replace(/^\/\//, "")}`; return `https://${trimmed.replace(/^\/\//, "")}`;
} }
/**
* Build a `tel:` URL from a free-form phone string. RFC 3966 allows only
* digits and a leading `+`, so we strip everything else (spaces, parens,
* dashes, slashes, dots, internal letters). The display string above the
* link keeps the human-readable formatting.
*/
function toTelUrl(phone: string): string {
const cleaned = phone.replace(/[^\d+]/g, "");
// Keep only a single leading '+' if present.
const normalized = cleaned.startsWith("+")
? "+" + cleaned.slice(1).replace(/\+/g, "")
: cleaned.replace(/\+/g, "");
return `tel:${normalized}`;
}
/** /**
* Turn a Shopify payment-gateway machine name (e.g. `shopify_payments`, * Turn a Shopify payment-gateway machine name (e.g. `shopify_payments`,
* `manual`, `bogus`) or a built-in manual-payment template name (e.g. * `manual`, `bogus`) or a built-in manual-payment template name (e.g.