Skip to content

Commit

Permalink
Merge pull request #205 from department-of-veterans-affairs/feature/1…
Browse files Browse the repository at this point in the history
…70-narin-link-analytics

[Feature] Add Analytics pass through events to Link
  • Loading branch information
narin authored Feb 26, 2024
2 parents 359a65d + 4d6aae7 commit a4b667d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 239 deletions.
56 changes: 25 additions & 31 deletions packages/components/src/components/Link/Link.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Meta, StoryObj } from '@storybook/react'
import { Platform, View } from 'react-native'
import { View } from 'react-native'
import React from 'react'

import { Link, LinkProps } from './Link'
Expand Down Expand Up @@ -30,8 +30,6 @@ export default meta

type Story = StoryObj<LinkProps>

const startTime = new Date()
const endTime = new Date(startTime.setMinutes(startTime.getMinutes() + 30))
const location = {
lat: 33.7764681,
long: -118.1189664,
Expand All @@ -43,36 +41,13 @@ const location = {
zipCode: '90822',
},
}
const getLocation = (): string => {
const { lat, long, name, address } = location
if (Platform.OS === 'ios' && lat && long) {
return name || ''
} else if (
address?.street &&
address?.city &&
address?.state &&
address?.zipCode
) {
return `${address.street} ${address.city}, ${address.state} ${address.zipCode}`
} else {
return name || ''
}
}

export const Calendar: Story = {
name: 'Calendar',
args: {
text: 'Add to calendar',
onPress: undefined, // Storybook sends a truthy function shell otherwise
type: 'calendar',
calendarData: {
title: 'Test',
startTime: startTime.getTime(),
endTime: endTime.getTime(),
location: getLocation(),
latitude: location.lat,
longitude: location.long,
},
},
}

Expand All @@ -84,6 +59,9 @@ export const Custom: Story = {
onPress: () => {
null
},
analytics: {
onPress: () => console.log('Analytics event: Pressed'),
},
},
}

Expand Down Expand Up @@ -124,13 +102,24 @@ export const Directions: Story = {

const paragraphText: LinkProps['paragraphText'] = [
// @ts-ignore: TS being wrong and thinking all should be LinkProps and none normalText
{text: 'A sentence may include a '},
{text: 'link that opens in a webview', type: 'custom', onPress: () => {null}, a11yLabel: 'a11y override' },
{ text: 'A sentence may include a ' },
{
text: 'link that opens in a webview',
type: 'custom',
onPress: () => {
null
},
a11yLabel: 'a11y override',
},
// @ts-ignore: TS being wrong and thinking all should be LinkProps and none normalText
{text: ' or a '},
{text: 'link that opens in an external app', type: 'url', url: 'https://department-of-veterans-affairs.github.io/va-mobile-app/design/intro'},
{ text: ' or a ' },
{
text: 'link that opens in an external app',
type: 'url',
url: 'https://department-of-veterans-affairs.github.io/va-mobile-app/design/intro',
},
// @ts-ignore: TS being wrong and thinking all should be LinkProps and none normalText
{text: '.'}
{ text: '.' },
]

export const Inline: Story = {
Expand Down Expand Up @@ -176,5 +165,10 @@ export const URL: Story = {
onPress: undefined, // Storybook sends a truthy function shell otherwise
type: 'url',
url: 'https://www.va.gov/',
analytics: {
onCancel: () => console.log('Analytics event: Canceled'),
onPress: () => console.log('Analytics event: Pressed'),
onConfirm: () => console.log('Analytics event: Confirmed'),
},
},
}
51 changes: 24 additions & 27 deletions packages/components/src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import {
import React, { FC, useState } from 'react'

import {
CalendarData,
FormDirectionsUrl,
LocationData,
OnPressCalendar,
isIOS,
leaveAppPromptText,
useExternalLink,
Expand All @@ -37,7 +35,8 @@ type nullTypeSpecifics = {

type calendar = Omit<nullTypeSpecifics, 'calendarData'> & {
type: 'calendar'
calendarData: CalendarData
/** Required onPress override logic */
onPress: () => void
}

type call = Omit<nullTypeSpecifics, 'phoneNumber'> & {
Expand Down Expand Up @@ -91,15 +90,11 @@ type linkTypes =
| text
| url

// TODO: Ticket 170 created to revisit adding analytics after calendar support added/or deemed infeasible
// type analytics = {
// onPress?: () => void
// onConfirm?: () => void
// hasCalendarPermission?: () => void
// onRequestCalendarPermission?: () => void
// onCalendarPermissionSuccess?: () => void
// onCalendarPermissionFailure?: () => void
// }
export type LinkAnalytics = {
onPress?: () => void
onConfirm?: () => void
onCancel?: () => void
}

export type LinkProps = linkTypes & {
/** Display text for the link */
Expand All @@ -115,7 +110,7 @@ export type LinkProps = linkTypes & {
/** Optional override text for leaving app confirmation prompt */
promptText?: leaveAppPromptText
/** Optional analytics event logging */
// analytics?: analytics
analytics?: LinkAnalytics
/** Internally used by 'inline' type. Not recommended for consumer use, but
* available to manually insert a link into a paragraph. True builds link
* component with RN Text instead of Pressable for improved wrapping behavior */
Expand All @@ -134,11 +129,10 @@ export const Link: FC<LinkProps> = ({
a11yLabel,
a11yHint,
promptText,
// analytics,
analytics,
inlineSingle,
testID,
// Type-specific props
calendarData,
locationData,
paragraphText,
phoneNumber,
Expand All @@ -150,53 +144,56 @@ export const Link: FC<LinkProps> = ({
const isDarkMode = colorScheme === 'dark'
const launchExternalLink = useExternalLink()

let _onPress: () => Promise<void> = async () => {
let _onPress: () => void = async () => {
null // Empty function to keep TS happy a function exists
}

/** Handler for links not using launchExternalLink prompt */
const customOnPress: () => void = () => {
if (analytics?.onPress) analytics.onPress()
if (onPress) onPress()
}

switch (type) {
case 'calendar':
icon = icon ? icon : { name: 'Calendar' }
_onPress = async (): Promise<void> => {
await OnPressCalendar(calendarData)
return
}
_onPress = customOnPress
break
case 'call':
icon = icon ? icon : { name: 'Phone' }
_onPress = async (): Promise<void> => {
launchExternalLink(`tel:${phoneNumber}`)
launchExternalLink(`tel:${phoneNumber}`, analytics)
}
break
case 'call TTY':
icon = icon ? icon : { name: 'TTY' }
_onPress = async (): Promise<void> => {
launchExternalLink(`tel:${TTYnumber}`)
launchExternalLink(`tel:${TTYnumber}`, analytics)
}
break
case 'custom':
icon = icon ? icon : 'no icon'
onPress = onPress
_onPress = customOnPress
break
case 'directions':
icon = icon ? icon : { name: 'Directions' }
const directions = FormDirectionsUrl(locationData)
_onPress = async (): Promise<void> => {
launchExternalLink(directions, promptText)
launchExternalLink(directions, analytics, promptText)
}
break
case 'inline':
return <InlineLink paragraphText={paragraphText} />
case 'text':
icon = icon ? icon : { name: 'Text' }
_onPress = async (): Promise<void> => {
launchExternalLink(`sms:${textNumber}`)
launchExternalLink(`sms:${textNumber}`, analytics)
}
break
case 'url':
icon = icon ? icon : { name: 'ExternalLink' }
_onPress = async (): Promise<void> => {
launchExternalLink(url, promptText)
launchExternalLink(url, analytics, promptText)
}
break
}
Expand Down Expand Up @@ -237,7 +234,7 @@ export const Link: FC<LinkProps> = ({
}

const pressableProps: PressableProps = {
onPress: onPress ? onPress : _onPress,
onPress: _onPress,
...a11yProps,
style: {
flexDirection: 'row',
Expand Down
Loading

0 comments on commit a4b667d

Please sign in to comment.