{"version":3,"file":"js/20536-ea0c3a8bbab9ebdda381.js","mappings":"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","sources":["webpack://StravaModern/./app/javascript/api/athlete/athlete.js","webpack://StravaModern/./app/javascript/apps/Microfrontend/styles.scss?dd46","webpack://StravaModern/./app/javascript/apps/Microfrontend/Microfrontend.js","webpack://StravaModern/./app/javascript/components/StravaAlert/StravaAlert.scss?a1ac","webpack://StravaModern/./app/javascript/components/StravaAlert/StravaAlert.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsButton/InviteFriendsButton.scss?21f1","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/constants/invite-friends-constants.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/utils/invite-friends-utils.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/InviteFriendsModal.scss?143d","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/state/InviteFriendsContext.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/state/InviteFriends.actions.js","webpack://StravaModern/./app/javascript/hooks/externalSocialPartners/useGoogle.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/EmailTabContent.scss?f2d3","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/LinkGoogleAccount/LinkGoogleAccount.scss?841b","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/LinkGoogleAccount/LinkGoogleAccount.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/GmailContactList/GmailContactList.scss?0bdd","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/GmailContactList/components/ContactEntry.scss?f7d7","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/EmailTabContent.utils.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/GmailContactList/components/ContactEntry.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/components/GmailContactList/GmailContactList.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/components/EmailTabContent/EmailTabContent.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsModal/InviteFriendsModal.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/state/InviteFriends.reducer.js","webpack://StravaModern/./app/javascript/components/shared/InviteFriends/components/InviteFriendsButton/InviteFriendsButton.js","webpack://StravaModern/./app/javascript/hooks/externalSocialPartners/useFacebook.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/LinkFacebookButton/LinkFacebookButton.scss?235a","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/LinkFacebookButton/LinkFacebookButton.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/LinkFacebookAccount/LinkFacebookAccount.scss?b824","webpack://StravaModern/./app/javascript/components/shared/friends/components/LinkFacebookAccount/LinkFacebookAccount.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/FacebookFriendList/InviteFriendsHeader/InviteFriendsHeader.scss?9139","webpack://StravaModern/./app/javascript/components/shared/friends/components/FacebookFriendList/InviteFriendsHeader/InviteFriendsHeader.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/FacebookFriendList/FacebookFriendList.js","webpack://StravaModern/./app/javascript/components/shared/friends/FindFacebookFriends/FindFacebookFriends.scss?ea55","webpack://StravaModern/./app/javascript/components/shared/friends/FindFacebookFriends/FindFacebookFriends.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/FriendList/FriendList.scss?6e23","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/FriendList/FriendList.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/AthleteInfo/AthleteInfo.scss?a41a","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/AthleteInfo/AthleteInfo.js","webpack://StravaModern/./app/javascript/components/shared/friends/utils/useCtaAction.js","webpack://StravaModern/./app/javascript/components/shared/friends/components/shared/FriendListItem/FriendListItem.js","webpack://StravaModern/./app/javascript/components/shared/friends/state/FriendsContext.js","webpack://StravaModern/./app/javascript/components/shared/friends/state/friendsActions.js","webpack://StravaModern/./app/javascript/components/shared/friends/state/friendsReducer.js","webpack://StravaModern/./app/javascript/components/shared/friends/utils/friendsConstants.js","webpack://StravaModern/./app/javascript/components/shared/friends/utils/friendsUtils.js","webpack://StravaModern/./app/javascript/constants/alerts/alert-types.js","webpack://StravaModern/./app/javascript/constants/follows/following-constants.js","webpack://StravaModern/./app/javascript/externalSocialPartners.js","webpack://StravaModern/./app/javascript/hooks/externalSocialPartners/constants/auth-status-constants.js","webpack://StravaModern/./app/javascript/components/shared/FormattedHTMLMessage/index.js","webpack://StravaModern/./app/javascript/utils/I18n.js","webpack://StravaModern/./app/javascript/utils/analytics.js","webpack://StravaModern/./app/javascript/utils/devUtils.js","webpack://StravaModern/./app/javascript/utils/generalUtils.js","webpack://StravaModern/./app/javascript/utils/networking-client.js","webpack://StravaModern/./app/javascript/utils/react-component-mounter.js","webpack://StravaModern/./app/javascript/utils/sentry.helper.js","webpack://StravaModern/./app/javascript/utils/sentry.js"],"sourcesContent":["import createNetworkingClient from 'utils/networking-client';\nimport { StatusCodes } from 'http-status-codes';\nimport { FOLLOWING_STATUS } from '../../constants/follows/following-constants';\nimport { logError } from '../../utils/sentry';\n\n/**\n * Follows an athlete on strava.\n *\n * @param {Object} param\n * @param {string} param.followerId - id for the athlete who is requesting the follow\n * @param {string} param.followingId - id for the athlete to be followed\n * @returns {Promise} - enum value PENDING or FOLLOWING\n */\nexport const followAthlete = ({ followerId, followingId }) => {\n return new Promise((resolve) => {\n createNetworkingClient()\n .post(`/athletes/${followerId}/follows`, {\n follow: {\n follower_id: followerId,\n following_id: followingId\n }\n })\n .then((response) => {\n if (response?.status === StatusCodes.OK) {\n const { data } = response;\n if (data.approved) {\n resolve(FOLLOWING_STATUS.following);\n } else {\n resolve(FOLLOWING_STATUS.pending);\n }\n } else {\n resolve(FOLLOWING_STATUS.error);\n // TODO log sentry error\n }\n })\n .catch(() => {\n resolve(FOLLOWING_STATUS.error);\n // TODO log sentry error\n });\n });\n};\n\nexport const bulkFollow = ({ followeeIds }) => {\n return new Promise((resolve) => {\n createNetworkingClient()\n .post('/athlete/bulk_follow', {\n followee_ids: followeeIds\n })\n .then((response) => {\n const { success, followed_athlete_ids: ids } = response.data;\n resolve({ success, followedAthleteIds: ids || [] });\n })\n .catch((e) => {\n logError(e);\n resolve({ success: false });\n });\n });\n};\n\nexport const unfollowAthlete = ({ followerId, followingId }) => {\n return new Promise((resolve) => {\n createNetworkingClient()\n .delete(\n `/athletes/${followerId}/follows/${followingId}`,\n {\n data: {\n follow: {\n follower_id: followerId,\n following_id: followingId\n }\n }\n },\n { headers: { Accept: 'text/javascript' } }\n )\n .then((response) => {\n if (response?.status === StatusCodes.NO_CONTENT) {\n resolve(true);\n } else {\n logError(response);\n resolve(false);\n }\n })\n .catch((e) => {\n logError(e);\n resolve(false);\n });\n });\n};\n\n/**\n * Gets suggested follow list\n *\n * @param {Object} param\n * @param {string} param.callsite - source making the get request\n * @returns {Promise} - list of suggested friends to follow\n */\nexport const getSuggestedFollows = ({ callsite }) => {\n return new Promise((resolve, reject) => {\n createNetworkingClient()\n .get('/athlete/suggested_follows', {\n params: { callsite }\n })\n .then((response) => {\n if (response?.status === StatusCodes.OK) {\n const { data } = response;\n resolve(data);\n } else {\n logError(response.error);\n resolve(response.error);\n }\n })\n .catch((e) => {\n logError(e);\n reject(e);\n });\n });\n};\n\nexport default { followAthlete, unfollowAthlete, getSuggestedFollows };\n","// extracted by mini-css-extract-plugin\nexport default {\"mfcontainer\":\"Microfrontend--mfcontainer--Sw1H-\"};","import React from 'react';\nimport {\n TranslationContext,\n AnalyticsContext,\n ErrorLoggingContext\n} from '@strava/container-context';\nimport { logError, logMessage } from '../../utils/sentry';\nimport I18n from '../../utils/I18n';\nimport styles from './styles.scss';\nimport { devLog } from '../../utils/devUtils';\n\n// We want to track each url that we use to load a remote entry,\n// because we want to check if we've already downloaded and avoid\n// downloading the same remote multiple times.\nconst remoteUrls = {};\n\n// We want to initialize the 'scope' (remote entry code) a single time,\n// and not many times for many different components.\n// Specifically, we only want to call this line once:\n// `containerResolve(window[scope].init(legacyShareScope));`\nconst initializedScopes = {};\n\nconst cleanup = (scriptElement) => {\n if (scriptElement.parentNode) {\n scriptElement.parentNode.removeChild(scriptElement);\n }\n};\n\nconst loadDynamicScript = (url) => {\n if (remoteUrls[url] == null) {\n remoteUrls[url] = new Promise((resolve, reject) => {\n // insert remote script into document and add\n // onerror and onload listeners that will finalize\n // installation\n const element = document.createElement('script');\n element.src = url;\n element.type = 'text/javascript';\n element.async = true;\n\n element.onload = () => {\n resolve(element);\n };\n\n element.onerror = () => {\n logMessage(`[loadDynamicScript] Script Error: ${url}`);\n reject(element);\n };\n\n document.head.appendChild(element);\n });\n }\n\n return remoteUrls[url];\n};\n\nconst cleanupScript = (url) => {\n if (remoteUrls[url]) {\n remoteUrls[url].then(cleanup, cleanup);\n }\n};\n\n// TODO: remove once we've upgraded to webpacker 6 (webpack 5)\n// The code here only supports consumption of federated modules\n// and does not allow hosting federated modules\n// copied from\n// https://github.com/module-federation/practical-module-federation/blob/master/chapter7/packages/home-wp4/src/App.jsx\nconst useDynamicScript = (url) => {\n const [isLoading, setIsLoading] = React.useState(true);\n const [failed, setFailed] = React.useState(false);\n\n React.useEffect(() => {\n if (!url) {\n return;\n }\n\n const promise = loadDynamicScript(url);\n\n setIsLoading(true);\n setFailed(false);\n\n promise.then(\n () => {\n devLog(`[useDynamicScript] Script Loaded: ${url}`);\n setIsLoading(false);\n },\n () => {\n setIsLoading(false);\n setFailed(true);\n }\n );\n\n // eslint-disable-next-line consistent-return\n return () => {\n // cleanup code to remove script added as part of loading\n // the remote federated module. This code is ran before\n // another execution of this useEffect is ran before\n // rendering and when the component unmounts\n devLog(`[useDynamicScript] Dynamic Script Removed: ${url}`);\n cleanupScript(url);\n };\n }, [url]);\n\n return {\n isLoading,\n failed\n };\n};\n\n// eslint-disable-next-line react/prop-types\nconst DynamicWidget = ({ url, scope, component, appContext }) => {\n const { isLoading, failed } = useDynamicScript(url);\n\n if (isLoading) {\n return null;\n }\n\n if (failed) {\n return

Failed to load dynamic script: {url}

;\n }\n\n const Component = React.lazy(\n () =>\n // moduleResolve is the reference to use to mark this\n // promise as completed/resolved.\n new Promise((moduleResolve) => {\n // signal webpacker to load the pages react\n // and create a share scope to initialize with\n // the component.\n // eslint-disable-next-line global-require\n const react = require('react');\n\n // eslint-disable-next-line global-require\n const translationscontext = require('@strava/container-context');\n\n const legacyShareScope = {\n react: {\n [react.version]: {\n get: () => {\n return () => react;\n },\n singleton: true,\n loaded: true,\n from: 'webpack4'\n }\n },\n // the context provider needs to be a singleton for the\n // shared info to be the same between container and MFE\n '@strava/container-context': {\n [translationscontext.version]: {\n get: () => {\n return () => translationscontext;\n },\n singleton: true,\n loaded: true,\n from: 'webpack4'\n }\n }\n };\n new Promise((containerResolve) => {\n // when we load the remoteEntry.js, it creates the scope\n // defined in the remote exposed components. We use the\n // pages shared scope to compare the react version on the\n // page vs the one of the remote component\n\n // Initialize a remote once even when multiple components use it\n if (initializedScopes[scope]) {\n containerResolve();\n } else {\n initializedScopes[scope] = true;\n containerResolve(window[scope].init(legacyShareScope));\n }\n }).then(() => {\n // finally, load the component/module and resolve\n // topmost promise\n window[scope].get(component).then((factory) => {\n moduleResolve(factory());\n });\n });\n })\n );\n\n return (\n \n \n \n );\n};\n\n// eslint-disable-next-line no-unused-vars,react/prop-types\nconst Microfrontend = ({ url, scope, component, appContext }) => (\n
\n {\n return window.Strava.ExternalAnalytics.trackV2(data);\n }\n }}\n >\n {\n return I18n.t(key, props);\n },\n getLanguage: () => {\n return I18n.language();\n }\n }}\n >\n \n \n \n \n \n
\n);\n\nexport default Microfrontend;\n","// extracted by mini-css-extract-plugin\nexport default {\"alert\":\"StravaAlert--alert--0tRrZ\",\"error\":\"StravaAlert--error--Cha6i\",\"success\":\"StravaAlert--success--52fm+\",\"warning\":\"StravaAlert--warning--JQQmd\",\"info\":\"StravaAlert--info---apjx\"};","import React from 'react';\nimport Alert from '@reach/alert';\nimport PropTypes from 'prop-types';\nimport clsx from '@strava/ui/clsx';\nimport { ALERT_TYPES } from 'constants/alerts/alert-types';\nimport styles from './StravaAlert.scss';\n\nconst StravaAlert = ({ children, className, severity, ...options }) => {\n return (\n \n {children}\n \n );\n};\n\nStravaAlert.defaultProps = {\n className: null\n};\n\nStravaAlert.propTypes = {\n severity: PropTypes.oneOf(Object.values(ALERT_TYPES)).isRequired,\n children: PropTypes.node.isRequired,\n className: PropTypes.string\n};\n\nexport default StravaAlert;\n","// extracted by mini-css-extract-plugin\nexport default {\"dashboard-sidebar\":\"InviteFriendsButton--dashboard-sidebar--BoJFT\",\"dashboardSidebar\":\"InviteFriendsButton--dashboard-sidebar--BoJFT\",\"onboarding\":\"InviteFriendsButton--onboarding--8znw0\",\"header-menu\":\"InviteFriendsButton--header-menu--VJUik\",\"headerMenu\":\"InviteFriendsButton--header-menu--VJUik\"};","export const I18nPrefix = 'components.invite_your_friends';\n\nexport default { I18nPrefix };\n","import I18n from 'utils/I18n';\nimport { I18nPrefix } from '../constants/invite-friends-constants';\n\nexport const t = (key, params) => I18n.t(`${I18nPrefix}.${key}`, { ...params });\n\nexport default { t };\n","// extracted by mini-css-extract-plugin\nexport default {\"tab-panels\":\"InviteFriendsModal--tab-panels--04Cpi\",\"tabPanels\":\"InviteFriendsModal--tab-panels--04Cpi\",\"tab-list\":\"InviteFriendsModal--tab-list--ClIK5\",\"tabList\":\"InviteFriendsModal--tab-list--ClIK5\"};","import React from 'react';\n\nconst InviteFriendsContext = React.createContext();\n// Context object accepts a displayName string property.\n// React DevTools uses this string to determine what to display for the context.\nInviteFriendsContext.displayName = 'InviteFriendsContext';\n\nexport function useInviteFriendsContext() {\n return React.useContext(InviteFriendsContext);\n}\n\nexport default InviteFriendsContext;\n","export const ADD_ALERT = 'ADD_ALERT';\nexport const CHANGE_TAB = 'CHANGE_TAB';\nexport const CLEAR_ALERT = 'CLEAR_ALERT';\nexport const CLEAR_EMAILS = 'CLEAR_EMAILS';\nexport const CLOSE_MODAL = 'CLOSE_MODAL';\nexport const OPEN_MODAL = 'OPEN_MODAL';\nexport const UPDATE_EMAILS = 'UPDATE_EMAILS';\nexport const UPDATE_FB_FRIENDS = 'UPDATE_FB_FRIENDS';\nexport const UPDATE_FB_FRIEND_FOLLOWING_STATUS =\n 'UPDATE_FB_FRIEND_FOLLOWING_STATUS';\nexport const UPDATE_INVITED_EMAILS_LIST = 'UPDATE_INVITED_EMAILS_LIST';\n\nexport default {\n ADD_ALERT,\n CHANGE_TAB,\n CLEAR_ALERT,\n CLOSE_MODAL,\n OPEN_MODAL,\n UPDATE_EMAILS,\n UPDATE_FB_FRIENDS,\n UPDATE_FB_FRIEND_FOLLOWING_STATUS,\n UPDATE_INVITED_EMAILS_LIST\n};\n","import { isNil } from 'lodash-es';\nimport { useEffect, useState } from 'react';\nimport createNetworkingClient from 'utils/networking-client';\nimport { injectGoogleScript } from 'externalSocialPartners';\nimport { timeout } from 'utils/devUtils';\nimport { AuthorizationStatus } from './constants/auth-status-constants';\nimport { logError } from '../../utils/sentry';\n\nconst PEOPLE_BASE_URL = 'https://people.googleapis.com/v1/';\n\n/**\n * Fetches a list of contacts from an authenticated google account.\n */\nconst useGoogle = ({ clientId, mocked = false }) => {\n const [contacts, setContacts] = useState([]);\n const [token, setToken] = useState(undefined);\n const [authorizationStatus, setAuthorizationStatus] = useState(\n AuthorizationStatus.INITIATED\n );\n\n const mockedConnections = () => {\n return new Promise((resolve) => {\n import('./data/google_connections_sample.json').then(async (c) => {\n await timeout(2000); // delaying things on purpose so we can see the spinner when mocking data\n resolve(c.connections);\n });\n });\n };\n\n /**\n * callback method called when the athlete signs into their google account.\n * This method attempts to retrieve contacts from the authenticated google account.\n */\n const handleSignInContactsScope = (tokenResponse) => {\n if (tokenResponse && tokenResponse.access_token) {\n const accessToken = tokenResponse.access_token;\n setToken(accessToken);\n\n const requestedScope =\n 'https://www.googleapis.com/auth/contacts.readonly';\n if (\n window.google.accounts.oauth2.hasGrantedAllScopes(\n tokenResponse,\n requestedScope\n )\n ) {\n const headers = { Authorization: `Bearer ${accessToken}` };\n const url = `${PEOPLE_BASE_URL}people/me/connections?personFields=names,photos,emailAddresses`;\n\n setAuthorizationStatus(AuthorizationStatus.AUTHORIZED);\n createNetworkingClient({ headers })\n .get(url, { params: { alt: 'json' } })\n .then(async (response) => {\n if (response && response.status === 200) {\n let { connections } = response.data;\n if (mocked) {\n connections = await mockedConnections();\n }\n setContacts(connections || []);\n setAuthorizationStatus(AuthorizationStatus.DATA_FETCHED);\n } else {\n setAuthorizationStatus(AuthorizationStatus.ERROR);\n logError(response.error);\n }\n })\n .catch((e) => {\n setAuthorizationStatus(AuthorizationStatus.ERROR);\n logError(e);\n });\n } else {\n // unauthorized\n setAuthorizationStatus(AuthorizationStatus.UNAUTHORIZED);\n window.google.accounts.oauth2.revoke(accessToken);\n }\n }\n };\n\n /**\n * Initializes a client that is used by athletes to request a token\n */\n const initializeGsiTokenClient = (scope, callback) => {\n const client = window.google.accounts.oauth2.initTokenClient({\n client_id: clientId,\n scope,\n callback\n });\n return client;\n };\n\n /**\n * injects GSI javascript library when the component that uses this hook is mounted\n */\n useEffect(() => {\n injectGoogleScript(async () => {\n if (mocked) {\n await timeout(2000);\n }\n setAuthorizationStatus(AuthorizationStatus.READY);\n });\n\n return () => {\n window.google.accounts.id.cancel();\n };\n }, [mocked]);\n\n const requestContacts = () => {\n setAuthorizationStatus(AuthorizationStatus.READY);\n setContacts([]);\n\n const requestedScope = 'https://www.googleapis.com/auth/contacts.readonly';\n\n const client = initializeGsiTokenClient(\n requestedScope,\n handleSignInContactsScope\n );\n client.requestAccessToken();\n };\n\n const disconnect = () => {\n setContacts([]);\n setAuthorizationStatus(AuthorizationStatus.READY);\n if (!isNil(token)) {\n window.google.accounts.oauth2.revoke(token);\n }\n };\n\n return {\n authorizationStatus,\n contacts,\n requestContacts,\n disconnect\n };\n};\n\nexport default useGoogle;\n","// extracted by mini-css-extract-plugin\nexport default {\"flex-grid\":\"EmailTabContent--flex-grid--Mga-F\",\"flexGrid\":\"EmailTabContent--flex-grid--Mga-F\",\"col\":\"EmailTabContent--col--QG6K6\",\"email-column\":\"EmailTabContent--email-column--C8DUs\",\"emailColumn\":\"EmailTabContent--email-column--C8DUs\",\"email-input\":\"EmailTabContent--email-input--Xkzv2\",\"emailInput\":\"EmailTabContent--email-input--Xkzv2\",\"email-body\":\"EmailTabContent--email-body--lNZfZ\",\"emailBody\":\"EmailTabContent--email-body--lNZfZ\",\"headline\":\"EmailTabContent--headline--wy3OM\",\"email-validation-error\":\"EmailTabContent--email-validation-error--KbaR0\",\"emailValidationError\":\"EmailTabContent--email-validation-error--KbaR0\",\"spinner\":\"EmailTabContent--spinner--7dkIg\",\"label\":\"EmailTabContent--label--VrcIr\",\"textarea\":\"EmailTabContent--textarea--1h97A\",\"error-border\":\"EmailTabContent--error-border--b31sY\",\"errorBorder\":\"EmailTabContent--error-border--b31sY\",\"send-button\":\"EmailTabContent--send-button--R4a2H\",\"sendButton\":\"EmailTabContent--send-button--R4a2H\"};","// extracted by mini-css-extract-plugin\nexport default {\"headline\":\"LinkGoogleAccount--headline--HvrbG\",\"content\":\"LinkGoogleAccount--content--wzkX7\",\"btn-label\":\"LinkGoogleAccount--btn-label--B5Uw8\",\"btnLabel\":\"LinkGoogleAccount--btn-label--B5Uw8\",\"gmail-button\":\"LinkGoogleAccount--gmail-button--u3CEQ\",\"gmailButton\":\"LinkGoogleAccount--gmail-button--u3CEQ\",\"active\":\"LinkGoogleAccount--active--EQMr3\",\"focus\":\"LinkGoogleAccount--focus--mpuxT\"};","import React from 'react';\nimport PropTypes from 'prop-types';\nimport GoogleButton from 'react-google-button';\nimport styles from './LinkGoogleAccount.scss';\n\nimport { t } from '../../../../../../utils/invite-friends-utils';\nimport { useInviteFriendsContext } from '../../../../../../state/InviteFriendsContext';\nimport { CLEAR_ALERT } from '../../../../../../state/InviteFriends.actions';\n\nconst LinkGoogleAccount = ({ requestContacts }) => {\n const { dispatch, track } = useInviteFriendsContext();\n\n const handleOnClick = () => {\n track({\n element: 'add_gmail_contacts',\n action: 'click',\n properties: { current_tab: 'email' }\n });\n dispatch({ type: CLEAR_ALERT });\n requestContacts();\n };\n return (\n <>\n

\n {t('modal.email.gmail_request.title')}\n

\n
\n

{t('modal.email.gmail_request.message')}

\n

\n {t('modal.email.gmail_request.disclaimer')}\n

\n
\n \n \n );\n};\n\nLinkGoogleAccount.propTypes = {\n requestContacts: PropTypes.func.isRequired\n};\n\nexport default LinkGoogleAccount;\n","// extracted by mini-css-extract-plugin\nexport default {\"headline\":\"GmailContactList--headline--wIxQ3\",\"disconnect-btn\":\"GmailContactList--disconnect-btn--ce6fi\",\"disconnectBtn\":\"GmailContactList--disconnect-btn--ce6fi\",\"search-input\":\"GmailContactList--search-input--pwQ4B\",\"searchInput\":\"GmailContactList--search-input--pwQ4B\",\"contact-list\":\"GmailContactList--contact-list--W2QgU\",\"contactList\":\"GmailContactList--contact-list--W2QgU\",\"fadeIn\":\"GmailContactList--fadeIn--ZgZO1\",\"spinner\":\"GmailContactList--spinner--Et4+N\",\"no-results\":\"GmailContactList--no-results--N3Xpe\",\"noResults\":\"GmailContactList--no-results--N3Xpe\",\"newKudo\":\"GmailContactList--newKudo--Hritm\",\"enterFadeOut\":\"GmailContactList--enterFadeOut--jZgsD\"};","// extracted by mini-css-extract-plugin\nexport default {\"athlete-metadata\":\"components--athlete-metadata--L1G69\",\"athleteMetadata\":\"components--athlete-metadata--L1G69\",\"name-and-email\":\"components--name-and-email--9n4AE\",\"nameAndEmail\":\"components--name-and-email--9n4AE\",\"name\":\"components--name--Bot7S\",\"disabled\":\"components--disabled--Pikmj\",\"email\":\"components--email--L8Vc8\",\"action-btn\":\"components--action-btn--ln6CC\",\"actionBtn\":\"components--action-btn--ln6CC\"};","import { compact, isEmpty, isNil, split, toLower, trim } from 'lodash-es';\n\n/**\n * Extracts the primary entry from an entries with multiple values.\n * If it cant be determined what the primary entry is, the first entry\n * in the list will be picked.\n *\n * entry example -\n * [ { displayName: 'Athlete Name_1', metadata: { primary: false } },\n * { displayName: 'Athlete Name_2', metadata: { primary: true } } ]\n *\n * @param {Object} entries - a list of entries with metadata that include a boolean which indicates\n * whether an entry is primary or not.\n * @returns\n */\nconst getPrimaryEntry = (entries) => {\n if (isNil(entries)) {\n return null;\n }\n const primary = entries.find((entry) => {\n const { metadata } = entry;\n return metadata ? metadata.primary : false;\n });\n return isEmpty(primary) ? entries[0] : primary;\n};\n\nexport const processContactsForUI = (contacts) => {\n const processedContacts = contacts.map((c, index) => {\n const { names, emailAddresses, photos } = c;\n\n const displayContact = {\n key: index,\n isOnStrava: false\n };\n // email address (required)\n if (isNil(getPrimaryEntry(emailAddresses))) {\n return null;\n }\n displayContact.email = getPrimaryEntry(emailAddresses).value;\n\n // display name (optional)\n if (isEmpty(names)) {\n displayContact.name = '';\n } else {\n displayContact.name = getPrimaryEntry(names).displayName;\n }\n // avatar picture (optional)\n if (isEmpty(photos)) {\n displayContact.picture = ''; // @strava/ui/Avatar requires blank string (vs null)\n } else {\n displayContact.picture = getPrimaryEntry(photos).url;\n }\n\n return displayContact;\n });\n return compact(processedContacts);\n};\n\nexport const extractEmailsFromString = (emails) => {\n return compact(split(toLower(emails), ',').map((email) => trim(email)));\n};\n\nexport default { processContactsForUI, extractEmailsFromString };\n","import React, { useEffect, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport Button from '@strava/ui/Button';\n\nimport { isEmpty } from 'lodash-es';\nimport Avatar from '@strava/ui/Avatar';\nimport clsx from '@strava/ui/clsx';\nimport {\n FOLLOW_ACTIONS,\n FOLLOWING_STATUS\n} from 'constants/follows/following-constants';\nimport { followAthlete } from 'api/athlete';\nimport styles from './ContactEntry.scss';\nimport { t } from '../../../../../../../utils/invite-friends-utils';\nimport { useInviteFriendsContext } from '../../../../../../../state/InviteFriendsContext';\nimport {\n UPDATE_EMAILS,\n ADD_ALERT,\n CLEAR_ALERT\n} from '../../../../../../../state/InviteFriends.actions';\nimport { extractEmailsFromString } from '../../../EmailTabContent.utils';\n\nconst ContactEntry = ({ contact }) => {\n const [config, setConfig] = useState({\n action: FOLLOW_ACTIONS.add,\n disabled: false\n });\n const [currentFollowingStatus, setCurrentFollowingStatus] = useState(\n contact.followingStatus\n );\n\n const [isLoading, setIsLoading] = useState(false);\n\n const { state, dispatch, track } = useInviteFriendsContext();\n const { emails, currentAthlete, invitedEmailsList } = state;\n\n useEffect(() => {\n let action;\n let disabled = false;\n if (contact.isOnStrava) {\n if (currentFollowingStatus === FOLLOWING_STATUS.pending) {\n action = FOLLOW_ACTIONS.followRequested;\n disabled = true;\n } else if (currentFollowingStatus === FOLLOWING_STATUS.following) {\n action = FOLLOW_ACTIONS.following;\n disabled = true;\n } else {\n action = contact.approveFollowers\n ? FOLLOW_ACTIONS.requestToFollow\n : FOLLOW_ACTIONS.follow;\n }\n } else {\n action = FOLLOW_ACTIONS.add;\n const { email } = contact;\n disabled =\n invitedEmailsList.includes(email) ||\n extractEmailsFromString(emails).includes(email);\n }\n setConfig((prev) => {\n return { ...prev, action, disabled };\n });\n }, [\n contact,\n contact.approveFollowers,\n contact.email,\n contact.isOnStrava,\n currentFollowingStatus,\n emails,\n invitedEmailsList\n ]);\n\n const disabledTextStyle = config.disabled ? styles.disabled : '';\n\n const handleBtnClick = (action) => {\n dispatch({ type: CLEAR_ALERT });\n track({\n element: `${action}_btn`,\n action: 'click',\n properties: {\n current_tab: 'email',\n athlete_id: contact.id\n }\n });\n\n switch (action) {\n case FOLLOW_ACTIONS.add: {\n const separator = isEmpty(emails) ? '' : ',';\n dispatch({\n type: UPDATE_EMAILS,\n payload: { emails: emails.concat(separator, contact.email) }\n });\n setConfig((prev) => {\n return { ...prev, disabled: true };\n });\n break;\n }\n\n case FOLLOW_ACTIONS.follow:\n case FOLLOW_ACTIONS.requestToFollow: {\n setIsLoading(true);\n followAthlete({\n followerId: currentAthlete.id,\n followingId: contact.id\n })\n .then((status) => {\n if (status === FOLLOWING_STATUS.error) {\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: {\n severity: 'error',\n message: t(`modal.errors.generic`)\n }\n }\n });\n } else {\n setCurrentFollowingStatus(status);\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n break;\n }\n default: // noop\n }\n };\n\n return (\n <>\n
\n \n
\n

\n {contact.name}\n

\n

\n {contact.email}\n

\n
\n
\n handleBtnClick(config.action)}\n disabled={config.disabled || isLoading}\n >\n {t(`modal.email.gmail_authorized.contact_cta.${config.action}`)}\n \n \n );\n};\n\nContactEntry.propTypes = {\n contact: PropTypes.shape({\n id: PropTypes.number,\n name: PropTypes.string,\n picture: PropTypes.string,\n badge: PropTypes.string,\n email: PropTypes.string.isRequired,\n isOnStrava: PropTypes.bool.isRequired,\n followingStatus: PropTypes.oneOf([\n 'following',\n 'pending',\n 'can_follow',\n 'can_request'\n ]),\n approveFollowers: PropTypes.bool\n }).isRequired\n};\n\nexport default ContactEntry;\n","import React, { useEffect, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport Button from '@strava/ui/Button';\nimport { isEmpty, size } from 'lodash-es';\nimport Spinner from '@strava/ui/Spinner';\nimport styles from './GmailContactList.scss';\n\nimport { t } from '../../../../../../utils/invite-friends-utils';\nimport ContactEntry from './components/ContactEntry';\nimport { useInviteFriendsContext } from '../../../../../../state/InviteFriendsContext';\nimport { CLEAR_ALERT } from '../../../../../../state/InviteFriends.actions';\n\nconst GmailContactList = ({ contacts, disconnect, isLoading }) => {\n const [searchKeyword, setSearchKeyword] = useState(''); // value entered in the search field\n const [filterResults, setFilterResults] = useState(contacts);\n\n const { dispatch, track } = useInviteFriendsContext();\n\n // keeps track if its the initial search results (with no filter applied).\n // This is necessary because filtered results change based on the search box input\n // and we dont want to re-register a screen-enter at that point.\n const initialResults = useRef(true);\n\n useEffect(() => {\n if (!isLoading && initialResults.current) {\n track({\n element: 'google_contacts_feed',\n action: 'screen_enter',\n properties: {\n current_tab: 'email',\n contacts_count: filterResults.length,\n already_on_strava_count: size(\n filterResults.filter((contact) => contact.isOnStrava)\n )\n }\n });\n initialResults.current = false;\n }\n }, [isLoading, filterResults, track]);\n\n useEffect(() => {\n setFilterResults(contacts);\n }, [contacts]);\n\n const filterContacts = (e) => {\n dispatch({\n type: CLEAR_ALERT\n });\n\n const keyword = e.target.value;\n if (keyword !== '') {\n const results = contacts.filter((contact) => {\n return (\n contact.name.toLowerCase().includes(keyword.toLowerCase()) ||\n contact.email.toLowerCase().includes(keyword.toLowerCase())\n );\n });\n setFilterResults(results);\n } else {\n setFilterResults(contacts); // show all contacts\n }\n setSearchKeyword(keyword);\n };\n\n const handleOnDisconnect = () => {\n track({\n element: 'disconnect_gmail_contacts',\n action: 'click',\n properties: { current_tab: 'email' }\n });\n dispatch({ type: CLEAR_ALERT });\n disconnect();\n };\n\n return (\n <>\n

\n {t('modal.email.gmail_authorized.title')}\n

\n \n {t('modal.email.gmail_authorized.disconnect')}\n \n\n \n\n \n \n );\n};\n\nconst ResultsFeed = ({ isLoading, results }) => {\n if (isLoading) {\n return (\n
\n \n
\n );\n }\n if (results && results.length > 0) {\n return (\n
    \n {results.map((contact) => (\n
  • \n \n
  • \n ))}\n
\n );\n }\n return (\n

\n {t('modal.email.gmail_authorized.no_results_found')}\n

\n );\n};\n\nResultsFeed.propTypes = {\n isLoading: PropTypes.bool.isRequired,\n results: PropTypes.arrayOf(PropTypes.shape({})).isRequired\n};\n\nGmailContactList.propTypes = {\n contacts: PropTypes.arrayOf(PropTypes.shape({})).isRequired,\n disconnect: PropTypes.func.isRequired,\n isLoading: PropTypes.bool.isRequired\n};\n\nexport default GmailContactList;\n","import React, { useEffect, useRef, useCallback } from 'react';\nimport Button from '@strava/ui/Button';\nimport useGoogle from 'hooks/externalSocialPartners/useGoogle';\nimport Spinner from '@strava/ui/Spinner';\nimport { AuthorizationStatus } from 'hooks/externalSocialPartners/constants/auth-status-constants';\nimport {\n remove,\n uniqBy,\n isEmpty,\n find,\n isNil,\n escape,\n toLower,\n orderBy\n} from 'lodash-es';\nimport createNetworkingClient from 'utils/networking-client';\nimport * as EmailValidator from 'email-validator';\nimport clsx from '@strava/ui/clsx';\nimport { timeout } from 'utils/generalUtils';\nimport StravaAlert from 'components/StravaAlert';\nimport { Markup } from 'interweave';\nimport { FOLLOWING_STATUS } from 'constants/follows/following-constants';\nimport { useSafeState, useSafeDispatch } from '@strava/react-hooks';\nimport { useInviteFriendsContext } from '../../../../state/InviteFriendsContext';\n\nimport styles from './EmailTabContent.scss';\nimport LinkGoogleAccount from './components/LinkGoogleAccount';\n\nimport { t } from '../../../../utils/invite-friends-utils';\nimport GmailContactList from './components/GmailContactList/GmailContactList';\nimport {\n extractEmailsFromString,\n processContactsForUI\n} from './EmailTabContent.utils';\nimport {\n ADD_ALERT,\n CLEAR_ALERT,\n CLEAR_EMAILS,\n UPDATE_EMAILS,\n UPDATE_INVITED_EMAILS_LIST\n} from '../../../../state/InviteFriends.actions';\nimport { logError } from '../../../../../../../utils/sentry';\n\nconst EmailTabContent = () => {\n const { state, dispatch, track } = useInviteFriendsContext();\n const safeDispatch = useSafeDispatch(dispatch);\n\n const { currentAthlete, googleClientId, mocked, emails, alert } = state;\n\n const {\n authorizationStatus,\n contacts,\n requestContacts,\n disconnect\n } = useGoogle({\n clientId: googleClientId,\n mocked\n });\n\n const [processedContacts, setProcessedContacts] = useSafeState([]);\n const [isProcessingContacts, setIsProcessingContacts] = useSafeState(true);\n const [isSendingEmails, setIsSendingEmails] = useSafeState(false);\n\n const emailInputRef = useRef(null);\n\n const emailMessage = t('modal.email.message');\n\n const dispatchAlert = useSafeDispatch(\n useCallback(\n ({ severity, message, target }) => {\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: {\n severity,\n message,\n target\n }\n }\n });\n },\n [dispatch]\n )\n );\n\n useEffect(() => {\n if (authorizationStatus === AuthorizationStatus.UNAUTHORIZED) {\n dispatchAlert({\n severity: 'warning',\n message: t('modal.email.unauthorized')\n });\n } else if (authorizationStatus === AuthorizationStatus.DATA_FETCHED) {\n // extract primary entries for each contact and remove entries without email addresses\n let results = processContactsForUI(contacts);\n // eliminate duplicates\n results = uniqBy(results, 'email');\n // remove logged-in athlete from the results\n remove(results, (c) => c.email === currentAthlete.email);\n\n if (isEmpty(results)) {\n setIsProcessingContacts(false);\n } else {\n const importedEmails = results.map((c) => c.email);\n\n // find friends who are already on strava and update their entries with strava data\n createNetworkingClient()\n .post('/athletes/email_contacts_on_strava', {\n emails: importedEmails\n })\n .then((response) => {\n if (response && response.status === 200) {\n const { data: friendsAlreadyOnStrava } = response;\n friendsAlreadyOnStrava.forEach((friend) => {\n const contact = find(\n results,\n (c) => toLower(c.email) === toLower(friend.email)\n );\n if (!isNil(contact)) {\n contact.isOnStrava = true;\n contact.id = friend.id;\n contact.picture = friend.picture;\n contact.approveFollowers = friend.approve_followers;\n contact.followingStatus = friend.following_status;\n contact.name = friend.display_name;\n contact.badge = friend.badge;\n }\n });\n } else {\n dispatchAlert({\n severity: 'error',\n message: t(`modal.errors.generic`)\n });\n }\n results = orderBy(\n results,\n [\n (contact) =>\n [\n FOLLOWING_STATUS.canFollow,\n FOLLOWING_STATUS.canRequest\n ].includes(contact.followingStatus), // 1st - followable athletes\n (contact) => contact.isOnStrava, // 2nd - all other strava athletes\n (contact) => isNil(contact.name) || contact.name === '', // 3rd - google contacts with display name\n (contact) => contact.name // 4th - the rest, order all groups by display name\n ],\n ['desc', 'desc', 'asc', 'asc']\n );\n\n setProcessedContacts(results);\n })\n .catch(() => {\n dispatchAlert({\n severity: 'error',\n message: t(`modal.errors.generic`)\n });\n })\n .finally(() => {\n setIsProcessingContacts(false);\n });\n }\n }\n }, [\n authorizationStatus,\n contacts,\n currentAthlete.email,\n dispatchAlert,\n setIsProcessingContacts,\n setProcessedContacts\n ]);\n\n useEffect(() => {\n if (emailInputRef.current) {\n emailInputRef.current.focus();\n }\n }, [emailInputRef]);\n\n // show error message to athlete when something goes wrong during authorization\n useEffect(() => {\n if (authorizationStatus === AuthorizationStatus.ERROR) {\n dispatchAlert({ severity: 'error', message: t(`modal.errors.generic`) });\n }\n }, [authorizationStatus, dispatchAlert]);\n\n const alreadyOnStravaMessage = (alreadyOnStrava) => {\n let message;\n const numOnStrava = alreadyOnStrava.length;\n\n if (numOnStrava === 1) {\n message = t('modal.email.already_on_strava', {\n email_address: escape(alreadyOnStrava[0])\n });\n } else if (numOnStrava === 2) {\n message = t('modal.email.x_and_y_already', {\n email_address: escape(alreadyOnStrava[0]),\n other_email_address: escape(alreadyOnStrava[1])\n });\n } else {\n message = t('modal.email.x_and_y_and_other_already', {\n email_address: escape(alreadyOnStrava[0]),\n other_email_address: escape(alreadyOnStrava[1]),\n count: numOnStrava - 2\n });\n }\n return message;\n };\n\n const isValidEmailList = (emailList) => {\n return isNil(emailList.find((email) => !EmailValidator.validate(email)));\n };\n\n const handleFormSubmission = async (event) => {\n event.preventDefault();\n\n dispatch({ type: CLEAR_ALERT });\n const emailList = extractEmailsFromString(emails);\n\n track({\n action: 'click',\n element: 'send_email',\n properties: {\n current_tab: 'email',\n email_count: emailList.length,\n is_valid_email_list: isValidEmailList(emailList),\n emails: emailList.toString()\n }\n });\n\n // validate emails\n for (let i = 0; i < emailList.length; i++) {\n if (!EmailValidator.validate(emailList[i])) {\n dispatchAlert({\n severity: 'error',\n message: t(`modal.errors.invalid_email`),\n target: 'email-input'\n });\n emailInputRef.current.focus();\n return;\n }\n }\n\n setIsSendingEmails(true);\n createNetworkingClient()\n .post(`/invites`, {\n to: emailList,\n body: emailMessage,\n invite_dialog: true\n })\n .then(async (response) => {\n if (response.status === 200) {\n const { sent, not_sent: notSent } = response.data;\n if (!isEmpty(sent)) {\n dispatchAlert({\n severity: 'success',\n message: t('modal.email.sent')\n });\n dispatch({\n type: UPDATE_INVITED_EMAILS_LIST,\n payload: sent\n });\n dispatch({ type: CLEAR_EMAILS });\n\n // `emails sent` message auto-clears after 4 seconds\n await timeout(4000);\n\n safeDispatch({ type: CLEAR_ALERT });\n }\n if (!isEmpty(notSent)) {\n const { already_on_strava: alreadyOnStrava } = notSent;\n if (!isEmpty(alreadyOnStrava)) {\n dispatchAlert({\n severity: 'warning',\n message: (\n \n )\n });\n }\n }\n } else {\n logError(response.error);\n dispatchAlert({\n severity: 'error',\n message: t('modal.errors.generic')\n });\n }\n })\n .catch((e) => {\n logError(e);\n dispatchAlert({\n severity: 'error',\n message: t('modal.errors.generic')\n });\n })\n .finally(() => {\n setIsSendingEmails(false);\n });\n };\n\n const handleInputChange = (event) => {\n dispatch({ type: CLEAR_ALERT });\n dispatch({ type: UPDATE_EMAILS, payload: { emails: event.target.value } });\n };\n\n return (\n <>\n {!isEmpty(alert) && (\n {alert.message}\n )}\n
\n
\n

{t('modal.email.subtitle')}

\n
\n \n \n\n \n \n\n \n {isSendingEmails\n ? t('modal.email.sending')\n : t('modal.email.send')}\n \n \n
\n
\n {[\n AuthorizationStatus.AUTHORIZED,\n AuthorizationStatus.DATA_FETCHED\n ].includes(authorizationStatus) && (\n \n )}\n {[\n AuthorizationStatus.READY,\n AuthorizationStatus.ERROR,\n AuthorizationStatus.UNAUTHORIZED\n ].includes(authorizationStatus) && (\n \n )}\n {authorizationStatus === AuthorizationStatus.INITIATED && (\n
\n \n
\n )}\n
\n
\n \n );\n};\n\nexport default EmailTabContent;\n","import React, { useEffect } from 'react';\n\nimport ModalWithTabs, {\n ModalTabs,\n ModalTabList,\n ModalTab,\n ModalTabPanels,\n ModalTabPanel\n} from '@strava/ui/ModalWithTabs';\nimport { t } from '../../utils/invite-friends-utils';\nimport styles from './InviteFriendsModal.scss';\nimport { useInviteFriendsContext } from '../../state/InviteFriendsContext';\nimport {\n CLEAR_ALERT,\n CHANGE_TAB,\n CLOSE_MODAL\n} from '../../state/InviteFriends.actions';\nimport EmailTabContent from './components/EmailTabContent/EmailTabContent';\nimport FindFacebookFriends from '../../../friends/FindFacebookFriends';\nimport { INVITE_FRIENDS } from '../../../friends/utils/friendsConstants';\n\nconst InviteFriendsModal = () => {\n const { state, dispatch, track } = useInviteFriendsContext();\n const {\n isModalOpen,\n modalTabIndex,\n currentAthlete,\n fbAppId,\n fbVersion,\n locale\n } = state;\n\n useEffect(() => {\n track({\n action: 'screen_enter'\n });\n }, [track]);\n\n const handleTabsChange = (selectedTab) => {\n dispatch({ type: CHANGE_TAB, payload: { modalTabIndex: selectedTab } });\n dispatch({ type: CLEAR_ALERT });\n track({\n element: selectedTab === 0 ? 'email' : 'facebook',\n action: 'click'\n });\n };\n\n return (\n dispatch({ type: CLOSE_MODAL })}\n title={t('modal.title')}\n aria-label={t('modal.aria-label')}\n data-cy=\"invite-friends-modal\"\n >\n \n \n {t('modal.email.title')}\n {t('modal.facebook.title')}\n \n \n \n \n \n \n \n \n \n \n \n );\n};\n\nexport default InviteFriendsModal;\n","import {\n ADD_ALERT,\n CHANGE_TAB,\n CLEAR_ALERT,\n CLEAR_EMAILS,\n CLOSE_MODAL,\n OPEN_MODAL,\n UPDATE_EMAILS,\n UPDATE_FB_FRIENDS,\n UPDATE_FB_FRIEND_FOLLOWING_STATUS,\n UPDATE_INVITED_EMAILS_LIST\n} from './InviteFriends.actions';\n\nexport function reducer(state, action) {\n switch (action.type) {\n case CLOSE_MODAL: {\n return { ...state, isModalOpen: false };\n }\n case OPEN_MODAL: {\n return { ...state, isModalOpen: true };\n }\n case UPDATE_EMAILS: {\n const { emails } = action.payload;\n return {\n ...state,\n emails\n };\n }\n\n case UPDATE_INVITED_EMAILS_LIST: {\n return {\n ...state,\n invitedEmailsList: [...state.invitedEmailsList, ...action.payload]\n };\n }\n\n case UPDATE_FB_FRIENDS: {\n const { fbFriends } = action.payload;\n return {\n ...state,\n fbFriends\n };\n }\n case UPDATE_FB_FRIEND_FOLLOWING_STATUS: {\n const { id, isFollowable, followingStatus } = action.payload;\n const friend = state.fbFriends[id];\n return {\n ...state,\n fbFriends: {\n ...state.fbFriends,\n [id]: { ...friend, isFollowable, followingStatus }\n }\n };\n }\n case ADD_ALERT: {\n const { alert } = action.payload;\n return {\n ...state,\n alert\n };\n }\n case CLEAR_ALERT: {\n return {\n ...state,\n alert: {}\n };\n }\n case CHANGE_TAB: {\n const { modalTabIndex } = action.payload;\n return { ...state, modalTabIndex };\n }\n case CLEAR_EMAILS: {\n return { ...state, emails: '' };\n }\n default: {\n throw new Error(`${action.type} - not recognized`);\n }\n }\n}\n\nexport default { reducer };\n","import React, { useCallback, useEffect, useMemo, useReducer } from 'react';\nimport PropTypes from 'prop-types';\n\nimport Button from '@strava/ui/Button';\nimport cx from '@strava/ui/clsx';\nimport { camelCase } from 'lodash-es';\nimport FacebookLogo from '@strava/icons/LogosFacebookXsmall';\nimport { trackV2 } from 'utils/analytics';\nimport { useInView } from 'react-intersection-observer';\nimport styles from './InviteFriendsButton.scss';\nimport { t } from '../../utils/invite-friends-utils';\nimport InviteFriendsModal from '../InviteFriendsModal/InviteFriendsModal';\nimport InviteFriendsContext from '../../state/InviteFriendsContext';\nimport { reducer } from '../../state/InviteFriends.reducer';\nimport { OPEN_MODAL } from '../../state/InviteFriends.actions';\n\nconst InviteFriendsButton = ({\n source,\n googleClientId,\n currentAthlete,\n locale,\n fbAppId,\n fbVersion,\n mocked,\n defaultTabIndex\n}) => {\n const [intersectionObserverRef, inView] = useInView({\n threshold: 1\n });\n\n const track = useCallback(\n (fields) => {\n trackV2({\n page: 'find_and_invite',\n category: 'connections',\n ...fields,\n properties: {\n source,\n default_tab: defaultTabIndex === 0 ? 'email' : 'facebook',\n ...fields.properties\n }\n });\n },\n [defaultTabIndex, source]\n );\n\n const [state, dispatch] = useReducer(reducer, {\n isModalOpen: false,\n googleClientId,\n currentAthlete,\n locale,\n fbAppId,\n fbVersion,\n fbFriends: {},\n invitedEmailsList: [],\n mocked,\n emails: '',\n alert: {},\n modalTabIndex: defaultTabIndex\n });\n\n const providerState = useMemo(\n () => ({\n state,\n dispatch,\n track\n }),\n [state, track]\n );\n\n const element = 'invite_friends_btn';\n\n useEffect(() => {\n if (inView) {\n track({ page: source, element, action: 'screen_enter' });\n }\n }, [inView, source, track]);\n\n const config = (() => {\n let cta = t('cta.find_and_invite_friends');\n let variant = 'text';\n let logo = null;\n\n if (source === 'onboarding') {\n variant = 'primary';\n cta = t('cta.connect_with_facebook');\n logo = ;\n } else if (\n [\n 'athlete_search',\n 'follows_following',\n 'follows_suggested',\n 'follows_followers',\n 'follows_blocked'\n ].includes(source)\n ) {\n variant = 'primary';\n } else if (source === 'header_menu') {\n cta = t('cta.find_friends');\n }\n return { cta, variant, logo };\n })();\n\n const handleButtonClick = () => {\n dispatch({ type: OPEN_MODAL });\n track({ page: source, element, action: 'click' }); // TODO confirm what page should be here\n };\n\n return (\n \n \n {config.logo}\n {config.cta}\n \n\n {state.isModalOpen && }\n \n );\n};\n\nInviteFriendsButton.defaultProps = {\n mocked: false,\n defaultTabIndex: 0 // defaults to first tab (email)\n};\n\nInviteFriendsButton.propTypes = {\n source: PropTypes.oneOf([\n 'athlete_search',\n 'dashboard_sidebar',\n 'follows_blocked',\n 'follows_followers',\n 'follows_following',\n 'follows_suggested',\n 'header_menu',\n 'onboarding' // facebook button on onboarding dashboard feed\n ]).isRequired,\n googleClientId: PropTypes.string.isRequired,\n mocked: PropTypes.bool,\n fbAppId: PropTypes.number.isRequired,\n fbVersion: PropTypes.string.isRequired,\n locale: PropTypes.string.isRequired,\n currentAthlete: PropTypes.shape({\n email: PropTypes.string.isRequired,\n id: PropTypes.number.isRequired\n }).isRequired,\n defaultTabIndex: PropTypes.oneOf([0, 1]) // 0 - email, 1 - FB\n};\n\nexport default InviteFriendsButton;\n","import { useEffect, useState } from 'react';\nimport createNetworkingClient from 'utils/networking-client';\nimport { injectFacebookScript } from 'externalSocialPartners';\nimport { difference, isEmpty, split } from 'lodash-es';\nimport { isDev, timeout } from 'utils/devUtils';\nimport { FOLLOWING_STATUS } from 'constants/follows/following-constants';\nimport { AuthorizationStatus } from './constants/auth-status-constants';\nimport { logError } from '../../utils/sentry';\n\n/**\n * Permissions required by FB graph endpoints - see https://developers.facebook.com/docs/permissions/reference/\n */\nconst Permissions = Object.freeze({\n FRIEND_LIST: ['user_friends']\n});\n\n/**\n *\n * Requests for user permissions before attempting to interact with Facebook Graph API.\n * eg. athletes can request for their friends which will prompt them to give strava the right permissions\n * if the permissions are missing.\n *\n * DEVELOPMENT NOTE: The FB api doesn't work locally, so we get around it with local data, while still\n * preserving the flow as much as possible\n *\n * @param {Object} arg\n * @param {number} arg.appId - Strava app client id which changes based on the environment (dev, staging and prod).\n * @param {string} arg.version - Facebook graph version.\n * @param {string} arg.locale - current athlete's locale\n * @param {boolean} arg.autoSync - whether to auto sync and try to pull FB friends before athlete clicks connect FB btn\n * (optional, defaults to true)\n * @param {string} arg.source - the page/component calling the hook\n * @returns {Object} response\n * @returns {boolean} response.ready - Whether FB javascript has been injected in the document.\n * @returns {string} response.authorizationStatus - enum value representing an athletes FB authorization state.\n * @returns {string} response.friends - Populated with a list of FB friends when requested by athlete.\n */\nconst useFacebook = ({ appId, version, locale, autoSync = true, source }) => {\n const [authorizationStatus, setAuthorizationStatus] = useState(\n AuthorizationStatus.INITIATED\n );\n const [fbFriends, setFbFriends] = useState([]);\n\n /**\n * If autoSync is on, during the first request to retrieve data from FB graph, we check if the athlete is already\n * connected to FB and if they have granted the right permissions for strava to retrieve\n * the requested data from their account without showing any FB verification/prompt UI.\n */\n const [isInitialRequest, setIsInitialRequest] = useState(true);\n\n /**\n * Inject FB graph api JS.\n *\n * Note - We need to do this for components that are mounted in haml templates since we are not\n * guaranteed that the script is available when the components attempt to request for FB graph data\n * on component mount.\n */\n useEffect(() => {\n injectFacebookScript({\n appId,\n version,\n locale,\n callback: () => setAuthorizationStatus(AuthorizationStatus.READY)\n });\n }, [appId, locale, version]);\n\n /**\n * If autoSync is off, we need to request permissions before we can proceed with logging in\n * and requesting friends\n */\n useEffect(() => {\n if (authorizationStatus === AuthorizationStatus.READY && !autoSync) {\n setAuthorizationStatus(AuthorizationStatus.REQUEST_PERMISSIONS);\n }\n }, [authorizationStatus, autoSync]);\n\n /**\n *\n * Checks to see if all the requested scopes were granted by the athlete.\n *\n * @param {Object} arg\n * @param {string} arg.grantedScopes - list of scopes that have been granted by the athlete\n * @param {string} arg.requestedScopes - list of scopes that are required by fb graph in order for strava\n * to retrieve requested user information.\n * @returns {boolean} - boolean value indicating whether the connected account has\n * all the required permissions or not.\n */\n const checkPermissions = ({ grantedScopes, requestedScopes }) => {\n if (isEmpty(grantedScopes)) {\n return false;\n }\n return difference(requestedScopes, grantedScopes).length === 0;\n };\n\n /**\n * FB graph `permissions` endpoint returns permissions in the following format\n * [{\n * \"permission\": \"user_friends\",\n * \"status\": \"granted\"\n * }, {...}, ...]\n * See - https://developers.facebook.com/docs/facebook-login/web/permissions/\n *\n * Retrieves only granted permissions and process them into an array - eg. ['user_friends', ... ]\n * which is then used by #checkPermissions in #stravaFbProxyPostPermissions\n *\n * @param {Array} data - the data from the `permissions` endpoint response\n */\n const getGrantedScopes = (data) => {\n return data.filter((p) => p.status === 'granted').map((p) => p.permission);\n };\n\n /**\n * Uses `active` as a proxy to check if the given token has all the permissions\n * that are requested.\n *\n * @param {Object} arg\n * @param {string} arg.accessToken - token for connected FB account\n * @param {Array} arg.requestedScopes - List of permissions required for the requested data to be retrieved\n * form FB graph\n * @returns {Promise} - boolean value indicating whether the connected account has\n * all the required permissions or not.\n */\n const stravaFbProxyPostPermissions = ({ accessToken, requestedScopes }) => {\n if (isDev()) {\n return new Promise((resolve) => {\n // import mock permissions data dynamically\n import('./data/facebook_permissions_sample.json').then((module) => {\n resolve(\n checkPermissions({\n grantedScopes: getGrantedScopes(module.default),\n requestedScopes\n })\n );\n });\n });\n }\n return new Promise((resolve, reject) => {\n createNetworkingClient()\n .post('/facebook_open_graph_actions/permissions', {\n access_token: accessToken\n })\n .then((response) => {\n if (response && response.status === 200) {\n resolve(\n checkPermissions({\n grantedScopes: getGrantedScopes(response.data),\n requestedScopes\n })\n );\n } else {\n reject(response.error);\n }\n })\n .catch((e) => reject(e));\n });\n };\n\n /**\n * Uses `active` as a proxy to retrieve friends data from FB graph\n *\n * @param {Object} arg\n * @param {string} arg.accessToken - token for connected FB account\n * @returns {Promise} - List of friends for the connected FB account.\n */\n const stravaFbProxyPostFriends = ({ accessToken }) => {\n if (isDev()) {\n return new Promise((resolve) => {\n // import mock friend data dynamically\n import('./data/facebook_friends_sample.json').then(async (module) => {\n await timeout(5);\n resolve(module.default);\n });\n });\n }\n return new Promise((resolve, reject) => {\n createNetworkingClient()\n .post('/facebook_open_graph_actions/friends', {\n access_token: accessToken,\n source\n })\n .then((response) => {\n if (response && response.status === 200) {\n resolve(response.data);\n } else {\n reject(response.error);\n }\n })\n .catch((e) => {\n reject(e);\n });\n });\n };\n\n /**\n * Hits Strava endpoint to get the Strava athletes associated with FB user ids\n *\n * @param {Object} arg\n * @param {Array} arg.facebookUIDs - list of facebook UIDs\n * @returns {Promise} - list of FB friends as Strava athletes\n */\n const stravaUsersFromFbIds = ({ facebookUIDs }) => {\n return new Promise((resolve, reject) => {\n createNetworkingClient()\n .post('/athletes/facebook_friends_on_strava', {\n facebook_uids: facebookUIDs\n })\n .then((response) => {\n if (response && response.status === 200) {\n resolve(response.data);\n } else {\n reject(response.error);\n }\n })\n .catch((e) => {\n reject(e);\n });\n });\n };\n\n /**\n * Uses FB graph to prompt the user to log in with the given list of\n * permissions.\n *\n * @param {Array} requestedScopes - list of permissions that are required to retrieve requested data\n * @returns {Promise} -An object with the following attributes:\n * `hasPermissions` - a boolean indicating whether the athlete authorized all permissions\n * `accessToken` - token for the connected FB account\n */\n const fbGraphApiLogin = (requestedScopes) => {\n return new Promise((resolve) => {\n const options = { scope: requestedScopes, return_scopes: true };\n if (authorizationStatus === AuthorizationStatus.REQUEST_NEW_PERMISSIONS) {\n options.auth_type = 'rerequest';\n }\n window.FB.login((response) => {\n if (response.authResponse) {\n const { accessToken, grantedScopes } = response.authResponse;\n /**\n * grantedScopes is a comma-separated list of granted scopes eg.\n * `email, user_friends ...`\n *\n * The next step generates an array of permissions eg. eg. ['user_friends', ... ]\n * which is then used by #checkPermissions\n */\n const grantedScopesList = split(grantedScopes, ',');\n resolve({\n hasPermissions: checkPermissions({\n grantedScopes: grantedScopesList,\n requestedScopes\n }),\n accessToken\n });\n } else {\n resolve({ hasPermissions: false });\n }\n }, options);\n });\n };\n\n /**\n * Checks the permissions for an already logged-in athlete and request for new permissions if the permissions\n * are insufficient. A UI dialog is used to request for more permissions if necessary.\n *\n * @param {Array} requestedScopes - list of permissions that are required to retrieve requested data\n * @returns {Promise} -An object with the following attributes:\n * `status` - enum representing the authorization status (see auth-status-constants#AuthorizationStatus)\n * `accessToken` - token for the connected FB account\n * */\n const requestPermissions = (requestedScopes) => {\n return new Promise((resolve, reject) => {\n if (autoSync && isInitialRequest) {\n /**\n * The component that is requesting data from FB has been mounted on the page, before prompting the user to\n * provide permissions, we check if they have already provided the permissions. If they are connected\n * but do not have the required permissions, then we update the status to `RequestNewPermissions` (which can\n * be used by the UI to show `Login with FB` button)\n */\n window.FB.getLoginStatus((response) => {\n // see https://developers.facebook.com/docs/facebook-login/web/ for possible status types\n if (response.status === 'connected') {\n const { accessToken } = response.authResponse;\n stravaFbProxyPostPermissions({\n accessToken,\n requestedScopes\n })\n .then((hasPermissions) => {\n const status = hasPermissions\n ? AuthorizationStatus.AUTHORIZED\n : AuthorizationStatus.REQUEST_NEW_PERMISSIONS;\n resolve({ status, accessToken });\n })\n .catch((e) => {\n reject(e);\n });\n } else {\n resolve({ status: AuthorizationStatus.REQUEST_NEW_PERMISSIONS });\n }\n });\n setIsInitialRequest(false);\n } else {\n /**\n * At this point, it has been determined that either the connected account does not have sufficient permissions or\n * an account is not connected at all.\n * The athlete is presented with the FB login button which when clicked will open a dialog requesting for\n * the required permissions. If they do not provide all of the permissions, the status will be updated to Unauthorized.\n * */\n fbGraphApiLogin(requestedScopes).then(\n ({ hasPermissions, accessToken }) => {\n const status = hasPermissions\n ? AuthorizationStatus.AUTHORIZED\n : AuthorizationStatus.UNAUTHORIZED;\n resolve({ status, accessToken });\n }\n );\n }\n });\n };\n\n /**\n * Request for friends data from FB graph\n */\n const requestFriends = () => {\n setAuthorizationStatus(AuthorizationStatus.READY); // reset auth status before flow\n requestPermissions(Permissions.FRIEND_LIST)\n .then(({ status, accessToken }) => {\n setAuthorizationStatus(status); // possible values - Authorized, UnAuthorized and NewPermissions\n if (status === AuthorizationStatus.AUTHORIZED) {\n stravaFbProxyPostFriends({ accessToken })\n .then((fbData) => {\n if (fbData.length > 0) {\n // pull out FB uids and get Strava athletes associated with them\n const facebookUIDs = fbData.map((friend) => friend.id);\n stravaUsersFromFbIds({ facebookUIDs })\n .then((stravaData) => {\n const camelCaseFriends = stravaData.map((athlete) => {\n return {\n id: athlete.id,\n picture: athlete.picture,\n followingStatus: athlete.following_status,\n isFollowable:\n athlete.following_status ===\n FOLLOWING_STATUS.canFollow ||\n athlete.following_status ===\n FOLLOWING_STATUS.canRequest,\n approveFollowers: athlete.approve_followers,\n badge: athlete.badge,\n displayName: athlete.display_name,\n subtitle: athlete.display_location\n };\n });\n setFbFriends(camelCaseFriends);\n setAuthorizationStatus(AuthorizationStatus.DATA_FETCHED);\n })\n .catch((e) => {\n // something went wrong while retrieving or processing Strava athletes from FB data\n setAuthorizationStatus(AuthorizationStatus.ERROR);\n logError(e);\n });\n } else {\n // there were no FB uids to get Strava athletes from\n setFbFriends([]);\n setAuthorizationStatus(AuthorizationStatus.DATA_FETCHED);\n }\n })\n .catch((e) => {\n // something went wrong while retrieving or processing friend data\n setAuthorizationStatus(AuthorizationStatus.ERROR);\n logError(e);\n });\n }\n })\n .catch((e) => {\n // something went wrong while requesting or checking permissions\n setAuthorizationStatus(AuthorizationStatus.ERROR);\n logError(e);\n });\n };\n\n return {\n fbFriends,\n authorizationStatus,\n requestFriends\n };\n};\n\nexport default useFacebook;\n","// extracted by mini-css-extract-plugin\nexport default {\"facebook-button\":\"LinkFacebookButton--facebook-button--+5rmt\",\"facebookButton\":\"LinkFacebookButton--facebook-button--+5rmt\",\"full-width\":\"LinkFacebookButton--full-width--WXCxj\",\"fullWidth\":\"LinkFacebookButton--full-width--WXCxj\"};","import React from 'react';\nimport PropTypes from 'prop-types';\nimport Button from '@strava/ui/Button';\nimport clsx from '@strava/ui/clsx';\nimport LogosFacebookSmall from '@strava/icons/LogosFacebookSmall';\nimport styles from './LinkFacebookButton.scss';\n\nconst LinkFacebookButton = ({ children, onClick, fullWidth, className }) => (\n \n \n {children}\n \n);\n\nLinkFacebookButton.defaultProps = {\n className: null,\n fullWidth: false\n};\n\nLinkFacebookButton.propTypes = {\n onClick: PropTypes.func.isRequired,\n children: PropTypes.node.isRequired,\n className: PropTypes.string,\n fullWidth: PropTypes.bool\n};\n\nexport default LinkFacebookButton;\n","// extracted by mini-css-extract-plugin\nexport default {\"headline\":\"LinkFacebookAccount--headline--H3YIb\"};","import React, { useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport { INVITE_FRIENDS } from '../../utils/friendsConstants';\nimport { t } from '../../utils/friendsUtils';\nimport { CLEAR_ALERT } from '../../state/friendsActions';\nimport { useFriendsContext } from '../../state/FriendsContext';\nimport LinkFacebookButton from '../shared/LinkFacebookButton';\n\nimport styles from './LinkFacebookAccount.scss';\n\n/* display connect with FB cta */\nconst LinkFacebookAccount = ({ requestFriends, authorizationStatus }) => {\n const { state, dispatch, track } = useFriendsContext();\n const { source } = state;\n const isInviteFriends = source === INVITE_FRIENDS;\n const analyticsBySource = isInviteFriends\n ? {\n element: 'connect_with_facebook',\n properties: { current_tab: 'facebook' }\n }\n : {\n element: 'connect_fb',\n properties: {}\n };\n\n useEffect(() => {\n track({\n ...analyticsBySource,\n action: 'screen_enter',\n properties: {\n ...analyticsBySource.properties,\n authorization_status: authorizationStatus\n }\n });\n }, [analyticsBySource, authorizationStatus, track]);\n\n const handleClick = () => {\n dispatch({ type: CLEAR_ALERT });\n track({\n ...analyticsBySource,\n action: 'click',\n properties: {\n ...analyticsBySource.properties\n }\n });\n requestFriends();\n };\n\n return (\n <>\n {isInviteFriends && (\n <>\n

{t('invite_friends.title')}

\n

{t('invite_friends.message')}

\n \n )}\n \n {isInviteFriends ? t('invite_friends.button') : t('onboarding.button')}\n \n \n );\n};\n\nLinkFacebookAccount.propTypes = {\n requestFriends: PropTypes.func.isRequired,\n authorizationStatus: PropTypes.string.isRequired\n};\n\nexport default LinkFacebookAccount;\n","// extracted by mini-css-extract-plugin\nexport default {\"fb-header\":\"InviteFriendsHeader--fb-header--EzGjF\",\"fbHeader\":\"InviteFriendsHeader--fb-header--EzGjF\",\"headline\":\"InviteFriendsHeader--headline--E93dU\"};","import React, { useState } from 'react';\nimport PropTypes from 'prop-types';\nimport Button from '@strava/ui/Button';\nimport { bulkFollow } from 'api/athlete';\nimport { FOLLOWING_STATUS } from 'constants/follows/following-constants';\nimport { useFriendsContext } from '../../../state/FriendsContext';\nimport {\n CLEAR_ALERT,\n ADD_ALERT,\n UPDATE_FRIEND_FOLLOWING_STATUS\n} from '../../../state/friendsActions';\nimport { t } from '../../../utils/friendsUtils';\n\nimport styles from './InviteFriendsHeader.scss';\n\n/* invite friends version of the fb friends modal has header with `follow all` button */\nconst InviteFriendsHeader = ({ sortedFriends }) => {\n const { state, dispatch, track } = useFriendsContext();\n const [isProcessing, setIsProcessing] = useState(false);\n\n const handleFollowAll = async () => {\n setIsProcessing(true);\n dispatch({ type: CLEAR_ALERT });\n\n const followeeIds = sortedFriends\n .filter((friend) => friend.isFollowable)\n .map((friend) => friend.id);\n\n bulkFollow({ followeeIds })\n .then(({ success, followedAthleteIds }) => {\n if (success) {\n followedAthleteIds.forEach((id) => {\n const friend = state.friends[id];\n dispatch({\n type: UPDATE_FRIEND_FOLLOWING_STATUS,\n payload: {\n id: friend.id,\n isFollowable: false,\n followingStatus: friend.approveFollowers\n ? FOLLOWING_STATUS.pending\n : FOLLOWING_STATUS.following\n }\n });\n });\n } else {\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: { severity: 'error', message: t(`errors.generic`) }\n }\n });\n }\n track({\n element: 'follow_all_btn',\n action: 'click',\n properties: {\n current_tab: 'facebook',\n follow_all_count: followeeIds.length,\n follow_all_status: success ? 'success' : 'error'\n }\n });\n })\n .finally(() => setIsProcessing(false));\n };\n\n return (\n
\n

\n {t('invite_friends.friends_on_strava')}\n

\n {sortedFriends.length > 0 && (\n // follow all\n friend.isFollowable)\n }\n onClick={handleFollowAll}\n >\n {t('cta_actions.follow_all')}\n \n )}\n
\n );\n};\n\nInviteFriendsHeader.propTypes = {\n sortedFriends: PropTypes.arrayOf(\n PropTypes.shape({\n id: PropTypes.number,\n picture: PropTypes.string,\n followingStatus: PropTypes.oneOf([\n FOLLOWING_STATUS.canFollow,\n FOLLOWING_STATUS.canRequest,\n FOLLOWING_STATUS.pending,\n FOLLOWING_STATUS.following\n ]),\n isFollowable: PropTypes.bool,\n approveFollowers: PropTypes.bool,\n badge: PropTypes.string,\n displayName: PropTypes.string,\n displayLocation: PropTypes.string\n })\n ).isRequired\n};\n\nexport default InviteFriendsHeader;\n","import React, { useEffect, useRef } from 'react';\nimport { sortBy } from 'lodash-es';\nimport { useFriendsContext } from '../../state/FriendsContext';\nimport { t } from '../../utils/friendsUtils';\nimport { INVITE_FRIENDS, ONBOARDING } from '../../utils/friendsConstants';\nimport InviteFriendsHeader from './InviteFriendsHeader';\nimport FriendList from '../shared/FriendList';\nimport FriendListItem from '../shared/FriendListItem';\n\n/* display list of friends with CTA to follow them */\nconst FacebookFriendList = () => {\n const { state, track } = useFriendsContext();\n const { friends, source } = state;\n const sortedFriends = sortBy(Object.values(friends), 'sortedIndex');\n const friendCount = sortedFriends.length;\n const onboardingFriendCountMessage = (() => {\n switch (friendCount) {\n case 0:\n return t('friend_list.no_fb_matches');\n case 1:\n return t('friend_list.one_friend_to_follow');\n default:\n return t('friend_list.more_friends_to_follow', {\n friend_count: friendCount\n });\n }\n })();\n\n // friends will change as friends get followed, so we\n // want to track the initial screen_enter\n const initialScreenEnter = useRef(true);\n useEffect(() => {\n if (initialScreenEnter.current) {\n const analytics = {\n element: 'facebook_friends_list',\n action: 'screen_enter',\n properties: {\n friends_count: friendCount\n }\n };\n if (source === INVITE_FRIENDS) {\n analytics.properties.current_tab = 'facebook';\n }\n track(analytics);\n initialScreenEnter.current = false;\n }\n }, [friendCount, source, track]);\n\n return (\n <>\n {source === INVITE_FRIENDS && (\n \n )}\n {source === ONBOARDING &&

{onboardingFriendCountMessage}

}\n {source === INVITE_FRIENDS && friendCount === 0 && (\n

{t('friend_list.no_fb_friends_on_strava')}

\n )}\n {friendCount > 0 && (\n \n {sortedFriends.map((friend) => (\n \n ))}\n \n )}\n \n );\n};\n\nexport default FacebookFriendList;\n","// extracted by mini-css-extract-plugin\nexport default {\"fb-panel\":\"FindFacebookFriends--fb-panel--xEyA+\",\"fbPanel\":\"FindFacebookFriends--fb-panel--xEyA+\",\"no-background\":\"FindFacebookFriends--no-background--2gPup\",\"noBackground\":\"FindFacebookFriends--no-background--2gPup\",\"center-spinner\":\"FindFacebookFriends--center-spinner--Wnal7\",\"centerSpinner\":\"FindFacebookFriends--center-spinner--Wnal7\"};","import React, { useEffect, useMemo, useReducer } from 'react';\nimport PropTypes from 'prop-types';\nimport { orderBy } from 'lodash-es';\nimport Spinner from '@strava/ui/Spinner';\nimport useFacebook from 'hooks/externalSocialPartners/useFacebook';\nimport { AuthorizationStatus } from 'hooks/externalSocialPartners/constants/auth-status-constants';\nimport StravaAlert from 'components/StravaAlert';\nimport { INVITE_FRIENDS, ONBOARDING } from '../utils/friendsConstants';\nimport { t } from '../utils/friendsUtils';\nimport FriendsContext from '../state/FriendsContext';\nimport { reducer } from '../state/friendsReducer';\nimport { ADD_ALERT, UPDATE_FRIENDS } from '../state/friendsActions';\nimport LinkFacebookAccount from '../components/LinkFacebookAccount';\nimport FacebookFriendList from '../components/FacebookFriendList';\n\nimport styles from './FindFacebookFriends.scss';\n\nconst FindFacebookFriends = ({\n track,\n currentAthlete,\n isVisible, // InviteFriends modal -> modalTablIndex === 1\n source, // 'invite_friends' or 'onboarding'\n fbApiProps,\n onFollowingFriendsChange\n}) => {\n const [state, dispatch] = useReducer(reducer, {\n currentAthlete,\n source,\n friends: {},\n followedFriends: {},\n alert: null,\n onFollowingFriendsChange\n });\n const { alert } = state;\n\n const providerState = useMemo(() => ({ state, dispatch, track }), [\n state,\n track\n ]);\n\n // don't have requestFriends be called as soon as FB script is ready. let athlete opt-in\n // to connecting FB in onboarding by clicking connect FB button\n const autoSync = source !== ONBOARDING;\n\n const { fbFriends, authorizationStatus, requestFriends } = useFacebook({\n ...fbApiProps,\n autoSync,\n source\n });\n\n useEffect(() => {\n // When component is visible, call requestFriends as soon as FB script is ready.\n // If user is not already logged in to FB, or if user is logged in to FB but\n // doesn't have the right permissions, auth status will be REQUEST_NEW_PERMISSIONS\n // and we show them the LinkFacebookAccount view\n if (\n autoSync &&\n isVisible &&\n authorizationStatus === AuthorizationStatus.READY\n ) {\n requestFriends();\n }\n // requestFriends deliberately left out to prevent multiple calls to this\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [authorizationStatus, isVisible]);\n\n // save friends to the shared state\n useEffect(() => {\n if (fbFriends.length > 0) {\n // INVITE_FRIENDS: list followable friends before friends already being followed\n // and sort alphabetically by name\n // ONBOARDING: list only followable friends\n const processedFriends =\n source === INVITE_FRIENDS\n ? orderBy(fbFriends, ['isFollowable', 'displayName'], ['desc', 'asc'])\n : fbFriends.filter((friend) => friend.isFollowable);\n // map friends array to object with the strava ids as the keys\n // save the index of the friend's position in the sorted array\n const friends = Object.fromEntries(\n processedFriends.map((friend, index) => [\n friend.id,\n { ...friend, sortedIndex: index }\n ])\n );\n dispatch({\n type: UPDATE_FRIENDS,\n payload: { friends }\n });\n }\n }, [dispatch, fbFriends, source]);\n\n useEffect(() => {\n if (authorizationStatus === AuthorizationStatus.ERROR) {\n // show error message to athlete when something goes wrong during authorization\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: { severity: 'error', message: t('errors.fb_error') }\n }\n });\n } else if (\n source === INVITE_FRIENDS &&\n authorizationStatus === AuthorizationStatus.UNAUTHORIZED\n ) {\n // INVITE_FRIENDS ONLY:\n // show warning message to athlete if they don't authorize FB permissions\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: {\n severity: 'warning',\n message: t('errors.unauthorized')\n }\n }\n });\n }\n }, [authorizationStatus, dispatch, source]);\n\n return (\n \n
\n {source === INVITE_FRIENDS && alert && (\n {alert.message}\n )}\n {source === ONBOARDING &&

{t('onboarding.message')}

}\n {[\n AuthorizationStatus.REQUEST_PERMISSIONS,\n AuthorizationStatus.REQUEST_NEW_PERMISSIONS,\n AuthorizationStatus.ERROR,\n AuthorizationStatus.UNAUTHORIZED\n ].includes(authorizationStatus) && (\n \n )}\n {source === ONBOARDING && alert && (\n \n {alert.message}\n \n )}\n {authorizationStatus === AuthorizationStatus.DATA_FETCHED && (\n \n )}\n {[\n AuthorizationStatus.INITIATED,\n AuthorizationStatus.READY,\n AuthorizationStatus.AUTHORIZED\n ].includes(authorizationStatus) && (\n
\n \n
\n )}\n
\n
\n );\n};\n\nFindFacebookFriends.defaultProps = {\n isVisible: true,\n onFollowingFriendsChange: () => {}\n};\n\nFindFacebookFriends.propTypes = {\n track: PropTypes.func.isRequired,\n currentAthlete: PropTypes.shape({\n id: PropTypes.number\n }).isRequired,\n fbApiProps: PropTypes.shape({\n appId: PropTypes.number,\n version: PropTypes.string,\n locale: PropTypes.string\n }).isRequired,\n source: PropTypes.oneOf([INVITE_FRIENDS, ONBOARDING]).isRequired,\n isVisible: PropTypes.bool,\n onFollowingFriendsChange: PropTypes.func\n};\n\nexport default FindFacebookFriends;\n","// extracted by mini-css-extract-plugin\nexport default {\"friend-list\":\"FriendList--friend-list--vRDGD\",\"friendList\":\"FriendList--friend-list--vRDGD\",\"scroll-shadow\":\"FriendList--scroll-shadow--0GFRE\",\"scrollShadow\":\"FriendList--scroll-shadow--0GFRE\"};","import React, { useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport clsx from '@strava/ui/clsx';\nimport { useFriendsContext } from '../../../state/FriendsContext';\nimport { INVITE_FRIENDS } from '../../../utils/friendsConstants';\n\nimport styles from './FriendList.scss';\n\nconst FriendList = ({ children }) => {\n const { state } = useFriendsContext();\n const { followedFriends, onFollowingFriendsChange } = state;\n\n useEffect(() => {\n onFollowingFriendsChange(followedFriends);\n }, [onFollowingFriendsChange, followedFriends]);\n\n return (\n \n {children}\n \n );\n};\n\nFriendList.propTypes = {\n children: PropTypes.node.isRequired\n};\n\nexport default FriendList;\n","// extracted by mini-css-extract-plugin\nexport default {\"list-row\":\"AthleteInfo--list-row--bM5xg\",\"listRow\":\"AthleteInfo--list-row--bM5xg\",\"athlete-metadata\":\"AthleteInfo--athlete-metadata--qzuP+\",\"athleteMetadata\":\"AthleteInfo--athlete-metadata--qzuP+\",\"name-and-subtitle\":\"AthleteInfo--name-and-subtitle--t+CuJ\",\"nameAndSubtitle\":\"AthleteInfo--name-and-subtitle--t+CuJ\",\"grayed-out\":\"AthleteInfo--grayed-out--ay4VH\",\"grayedOut\":\"AthleteInfo--grayed-out--ay4VH\"};","import React from 'react';\nimport PropTypes from 'prop-types';\nimport Avatar from '@strava/ui/Avatar';\nimport clsx from '@strava/ui/clsx';\nimport { isMobile } from 'utils/generalUtils';\nimport { useFriendsContext } from '../../../state/FriendsContext';\nimport { INVITE_FRIENDS } from '../../../utils/friendsConstants';\n\nimport styles from './AthleteInfo.scss';\n\nconst AthleteInfo = ({ friend, children }) => {\n const { state } = useFriendsContext();\n return (\n
  • \n \n \n
    \n

    {friend.displayName}

    \n

    {friend.subtitle}

    \n
    \n \n {children}\n
  • \n );\n};\n\nAthleteInfo.propTypes = {\n friend: PropTypes.shape({\n isFollowable: PropTypes.bool,\n picture: PropTypes.string,\n badge: PropTypes.string,\n displayName: PropTypes.string,\n subtitle: PropTypes.string\n }).isRequired,\n children: PropTypes.node.isRequired\n};\n\nexport default AthleteInfo;\n","import { useEffect, useState } from 'react';\nimport {\n FOLLOW_ACTIONS,\n FOLLOWING_STATUS\n} from 'constants/follows/following-constants';\n\nexport const useCtaAction = (friend) => {\n const { approveFollowers, followingStatus } = friend;\n const [cta, setCta] = useState(FOLLOW_ACTIONS.follow);\n\n useEffect(() => {\n if (followingStatus === FOLLOWING_STATUS.pending) {\n setCta(FOLLOW_ACTIONS.followRequested);\n } else if (followingStatus === FOLLOWING_STATUS.following) {\n setCta(FOLLOW_ACTIONS.following);\n } else {\n setCta(\n approveFollowers\n ? FOLLOW_ACTIONS.requestToFollow\n : FOLLOW_ACTIONS.follow\n );\n }\n }, [approveFollowers, followingStatus]);\n\n return cta;\n};\n\nexport default useCtaAction;\n","import React, { useState } from 'react';\nimport PropTypes from 'prop-types';\nimport Button from '@strava/ui/Button';\nimport { FOLLOWING_STATUS } from 'constants/follows/following-constants';\nimport { followAthlete, unfollowAthlete } from 'api/athlete';\nimport AthleteInfo from '../AthleteInfo';\nimport { useFriendsContext } from '../../../state/FriendsContext';\nimport {\n ADD_ALERT,\n CLEAR_ALERT,\n ADD_ATHLETE,\n REMOVE_ATHLETE,\n UPDATE_FRIEND_FOLLOWING_STATUS\n} from '../../../state/friendsActions';\nimport { t } from '../../../utils/friendsUtils';\nimport {\n INVITE_FRIENDS,\n SUGGESTED_FRIENDS\n} from '../../../utils/friendsConstants';\nimport useCtaAction from '../../../utils/useCtaAction';\n\nconst FriendListItem = ({ id }) => {\n // retrieve friend from shared state\n const { state, dispatch, track } = useFriendsContext();\n const { friends, currentAthlete, source } = state;\n const friend = friends[id];\n const [isProcessing, setIsProcessing] = useState(false);\n\n const cta = useCtaAction(friend);\n\n const handleFollowAthlete = () => {\n followAthlete({\n followerId: currentAthlete.id,\n followingId: friend.id\n })\n .then((status) => {\n const analytics = {\n element: source === INVITE_FRIENDS ? `${cta}_btn` : cta,\n action: 'click',\n properties: {\n athlete_id: friend.id,\n following_status: status\n }\n };\n if (source === INVITE_FRIENDS) {\n analytics.properties.current_tab = 'facebook';\n }\n track(analytics);\n if (status === FOLLOWING_STATUS.error) {\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: { severity: 'error', message: t(`errors.generic`) }\n }\n });\n } else {\n dispatch({\n type: UPDATE_FRIEND_FOLLOWING_STATUS,\n payload: {\n id: friend.id,\n isFollowable: false,\n followingStatus: status\n }\n });\n dispatch({\n type: ADD_ATHLETE,\n payload: { friend }\n });\n }\n })\n .finally(() => {\n setIsProcessing(false);\n });\n };\n\n const handleUnfollowAthlete = () => {\n unfollowAthlete({\n followerId: currentAthlete.id,\n followingId: friend.id\n })\n .then((success) => {\n track({\n action: 'click',\n element: 'unfollow',\n properties: {\n athlete_id: friend.id,\n success\n }\n });\n if (success) {\n dispatch({\n type: UPDATE_FRIEND_FOLLOWING_STATUS,\n payload: {\n id: friend.id,\n isFollowable: true,\n followingStatus: friend.approveFollowers\n ? FOLLOWING_STATUS.canRequest\n : FOLLOWING_STATUS.canFollow\n }\n });\n dispatch({\n type: REMOVE_ATHLETE,\n payload: {\n id: friend.id\n }\n });\n } else {\n dispatch({\n type: ADD_ALERT,\n payload: {\n alert: { severity: 'error', message: t(`errors.generic`) }\n }\n });\n }\n })\n .finally(() => {\n setIsProcessing(false);\n });\n };\n\n const handleBtnClick = () => {\n setIsProcessing(true);\n dispatch({ type: CLEAR_ALERT });\n\n if (friend.isFollowable) {\n handleFollowAthlete();\n } else {\n handleUnfollowAthlete();\n }\n };\n\n return (\n \n \n {t(`cta_actions.${cta}`)}\n \n \n );\n};\n\nFriendListItem.propTypes = {\n id: PropTypes.number.isRequired\n};\n\nexport default FriendListItem;\n","import { useContext, createContext } from 'react';\n\nconst FriendsContext = createContext();\nFriendsContext.displayName = 'FriendsContext';\n\nexport const useFriendsContext = () => {\n const context = useContext(FriendsContext);\n\n if (!context) {\n throw new Error(\n 'useFriendsContext must be used within the FriendsContext.Provider'\n );\n }\n\n return context;\n};\n\nexport default FriendsContext;\n","export const ADD_ALERT = 'ADD_ALERT';\nexport const CLEAR_ALERT = 'CLEAR_ALERT';\nexport const ADD_ATHLETE = 'ADD_ATHLETE';\nexport const REMOVE_ATHLETE = 'REMOVE_ATHLETE';\nexport const UPDATE_FRIENDS = 'UPDATE_FRIENDS';\nexport const UPDATE_FRIEND_FOLLOWING_STATUS = 'UPDATE_FRIEND_FOLLOWING_STATUS';\n\nexport default {\n ADD_ALERT,\n CLEAR_ALERT,\n ADD_ATHLETE,\n REMOVE_ATHLETE,\n UPDATE_FRIENDS,\n UPDATE_FRIEND_FOLLOWING_STATUS\n};\n","import {\n ADD_ALERT,\n CLEAR_ALERT,\n ADD_ATHLETE,\n REMOVE_ATHLETE,\n UPDATE_FRIENDS,\n UPDATE_FRIEND_FOLLOWING_STATUS\n} from './friendsActions';\n\nexport const reducer = (state, action) => {\n switch (action.type) {\n case ADD_ALERT: {\n const { alert } = action.payload;\n return {\n ...state,\n alert\n };\n }\n case CLEAR_ALERT: {\n return {\n ...state,\n alert: null\n };\n }\n case ADD_ATHLETE: {\n const { friend } = action.payload;\n return {\n ...state,\n followedFriends: {\n ...state.followedFriends,\n [friend.id]: friend\n }\n };\n }\n case REMOVE_ATHLETE: {\n const { id } = action.payload;\n const { [id]: _, ...rest } = state.followedFriends;\n return {\n ...state,\n followedFriends: { ...rest }\n };\n }\n case UPDATE_FRIENDS: {\n const { friends } = action.payload;\n return {\n ...state,\n friends\n };\n }\n case UPDATE_FRIEND_FOLLOWING_STATUS: {\n const { id, isFollowable, followingStatus } = action.payload;\n const friend = state.friends[id];\n return {\n ...state,\n friends: {\n ...state.friends,\n [id]: { ...friend, isFollowable, followingStatus }\n }\n };\n }\n default:\n throw new Error(`${action.type} not recognized`);\n }\n};\n\nexport default { reducer };\n","export const ONBOARDING = 'onboarding';\nexport const INVITE_FRIENDS = 'invite_friends';\nexport const SUGGESTED_FRIENDS = 'suggested_friends';\n\nexport default { ONBOARDING, INVITE_FRIENDS, SUGGESTED_FRIENDS };\n","import I18n from 'utils/I18n';\n\nexport const t = (key, params) =>\n I18n.t(`components.friends.${key}`, { ...params });\n\nexport default { t };\n","export const ALERT_TYPES = Object.freeze({\n warning: 'warning',\n error: 'error',\n info: 'info',\n success: 'success'\n});\n\nexport default { ALERT_TYPES };\n","export const FOLLOWING_STATUS = Object.freeze({\n following: 'following',\n pending: 'pending',\n error: 'error',\n canFollow: 'can_follow',\n canRequest: 'can_request'\n});\n\nexport const FOLLOW_ACTIONS = Object.freeze({\n add: 'add',\n followRequested: 'follow_requested',\n following: 'following',\n requestToFollow: 'request_to_follow',\n follow: 'follow'\n});\n","import { replace } from 'lodash-es';\nimport { logError } from './utils/sentry';\n\nconst appendScriptToBody = ({ script, name }) => {\n if (document.querySelector('body')) {\n document.querySelector('body').appendChild(script);\n } else {\n const e = new Error(`Failed to inject ${name} script`);\n logError(e);\n }\n};\n\n// this injects window.google and not the legacy window.gapi JS api\nexport const injectGoogleScript = (callback) => {\n if (!window.google) {\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.onload = callback;\n script.id = 'google-client-script';\n appendScriptToBody({ script, name: 'google gsi' });\n } else {\n callback();\n }\n};\n\nexport const injectAppleScript = (locale = 'en_US') => {\n if (!window.apple) {\n const script = window.document.createElement('script');\n const formattedLocale = replace(locale, '-', '_');\n script.src = `https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/${formattedLocale}/appleid.auth.js`;\n script.async = true;\n appendScriptToBody({ script, name: 'apple' });\n }\n};\n\nexport const injectFacebookScript = ({\n appId,\n version,\n callback,\n locale = 'en_US'\n}) => {\n if (!window.FB) {\n window.fbAsyncInit = () => {\n // ref - https://developers.facebook.com/docs/javascript/reference/FB.init/v13.0\n window.FB.init({\n appId,\n xfbml: true,\n version,\n status: true,\n cookie: true\n });\n callback();\n };\n\n // facebook uses format ll_CC - see https://developers.facebook.com/docs/javascript/internationalization\n const formattedLocale = replace(locale, '-', '_');\n\n const script = window.document.createElement('script');\n script.src = `https://connect.facebook.net/${formattedLocale}/sdk.js`;\n script.async = true;\n appendScriptToBody({ script, name: 'facebook-jssdk' });\n } else {\n callback();\n }\n};\n\nexport default { injectGoogleScript, injectAppleScript, injectFacebookScript };\n","/**\n * AUTHORIZED - the athlete has granted all the necessary permissions and is ready to fetch data\n * DATA_FETCHED - the athlete has granted all the necessary permissions and data has been fetched successfully\n * ERROR - an error occurred while fetching or processing data\n * INITIATED - social hook has been attached to the component\n * READY - external partner JS has been injected or verified to be present on the page\n * REQUEST_PERMISSION - athlete needs to grant permissions for the request to take place\n * REQUEST_NEW_PERMISSION - the athlete needs to grant more permissions for the request to proceed\n * UNAUTHORIZED - the athlete has denied giving permissions after being prompted to do so\n */\nexport const AuthorizationStatus = Object.freeze({\n AUTHORIZED: 'AUTHORIZED',\n DATA_FETCHED: 'DATA_FETCHED',\n ERROR: 'ERROR',\n INITIATED: 'INITIATED',\n READY: 'READY',\n REQUEST_PERMISSIONS: 'REQUEST_PERMISSIONS',\n REQUEST_NEW_PERMISSIONS: 'REQUEST_NEW_PERMISSIONS',\n UNAUTHORIZED: 'UNAUTHORIZED'\n});\n\nexport default { AuthorizationStatus };\n","import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst FormattedHTMLMessage = ({ tagName, message, className, onLinkClick }) => {\n const handleLinkClick = (e) => {\n if (e.target.nodeName === 'A' && !!onLinkClick) {\n onLinkClick(e);\n }\n };\n\n return React.createElement(tagName, {\n className,\n dangerouslySetInnerHTML: {\n __html: message\n },\n onClick: handleLinkClick\n });\n};\n\nFormattedHTMLMessage.propTypes = {\n message: PropTypes.string.isRequired,\n tagName: PropTypes.string,\n className: PropTypes.string,\n onLinkClick: PropTypes.func\n};\n\nFormattedHTMLMessage.defaultProps = {\n tagName: 'span',\n className: null,\n onLinkClick: null\n};\n\nexport default FormattedHTMLMessage;\n","import React from 'react';\n\nimport FormattedHTMLMessage from '../components/shared/FormattedHTMLMessage';\n\nfunction t(key, props = {}) {\n return window.Strava.I18n.Locale.t(key, props);\n}\n\nfunction elevationFormatter(unitSystem) {\n return new window.Strava.I18n.ElevationFormatter(unitSystem);\n}\n\nfunction elevationLabelFormatter(unitSystem) {\n return new window.Strava.I18n.ChartLabelElevationFormatter(unitSystem);\n}\n\nfunction distanceFormatter(unitSystem) {\n return new window.Strava.I18n.DistanceFormatter(unitSystem);\n}\n\nfunction distanceLabelFormatter(unitSystem) {\n return new window.Strava.I18n.ChartLabelDistanceFormatter(unitSystem);\n}\n\nfunction distancePerTimeFormatter(unitSystem) {\n return new window.Strava.I18n.DistancePerTimeFormatter(unitSystem);\n}\n\nfunction distancePerTimeLabelFormatter(unitSystem) {\n return new window.Strava.I18n.ChartLabelDistancePerTimeFormatter(unitSystem);\n}\n\nfunction percentFormatter() {\n return new window.Strava.I18n.PercentFormatter();\n}\n\nfunction timespanFormatter() {\n return new window.Strava.I18n.TimespanFormatter();\n}\n\nexport default {\n t,\n t_html(key, props = {}, options = {}) {\n return ;\n },\n elevationFormatter,\n elevationLabelFormatter,\n distanceFormatter,\n distanceLabelFormatter,\n distancePerTimeFormatter,\n distancePerTimeLabelFormatter,\n percentFormatter,\n timespanFormatter,\n language() {\n return window.Strava.I18n.Locales.LANGUAGE_CODE;\n },\n measurementUnits() {\n return window.Strava.I18n.UnitSystem.get();\n }\n};\n","import { logMessage } from './sentry';\n\nexport function trackV2({ category, page, action, element, properties = {} }) {\n try {\n window.Strava.ExternalAnalytics.trackV2({\n category,\n page,\n action,\n element,\n properties\n });\n } catch (e) {\n logMessage(\n `Could not execute Strava.ExternalAnalytics.trackV2 event with the category:action ${category}:${action}`,\n e\n );\n }\n}\n\nexport default {\n trackV2\n};\n","/**\n * dev utils to make local development easier (dynamically-imported mock data,\n * dev-only console logs, etc.)\n */\n\nexport const isDev = () => {\n return process.env.NODE_ENV === 'development';\n};\n\nexport const isTest = () => process.env.NODE_ENV === 'test';\n\nexport const devLog = (string) => {\n if (isDev() || window?.StravaDevTools?.enabled) {\n // eslint-disable-next-line no-console\n console.log(string);\n }\n};\n\nexport const timeout = (ms) => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\nexport default { isDev, devLog, timeout };\n","import { split } from 'lodash-es';\n\nexport { timeout } from './devUtils';\n\nexport const generateRandomId = () =>\n Math.random()\n .toString(36)\n .substring(2);\n\n// Capitalizes all the words and replaces some characters in the string to create a nicer looking title.\n// eg. 'man from the boondocks' => 'Man From The Boondocks'\nconst titleize = (str) =>\n str.replace(\n /\\w\\S*/g,\n (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()\n );\n\nexport const displayName = (\n { firstName = '', lastName = '' },\n options = { forceAnonymize: false, maxLength: 100 }\n) => {\n const { maxLength, forceAnonymize } = options;\n const fullName = `${firstName} ${lastName}`;\n\n if (forceAnonymize || fullName.length > maxLength) {\n if (firstName.length > maxLength - 3) {\n return `${titleize(\n firstName.substring(0, maxLength - 4)\n )}... ${lastName.charAt(0).toUpperCase()}.`;\n }\n return `${titleize(firstName)} ${lastName.charAt(0).toUpperCase()}.`;\n }\n return fullName.trim();\n};\n\nexport const isMobile = () => window.navigator.userAgent.includes('Mobile');\n\nexport const dateYearsAgo = (years) => {\n const d = new Date(new Date().toDateString());\n d.setFullYear(d.getFullYear() - years);\n return d;\n};\n\nexport const parseServerDateString = (date) => {\n const dobArray = split(date, '-');\n return {\n year: parseInt(dobArray[0], 10),\n month: parseInt(dobArray[1], 10),\n day: parseInt(dobArray[2], 10)\n };\n};\n\nexport default {\n displayName,\n generateRandomId,\n isMobile,\n dateYearsAgo,\n parseServerDateString\n};\n","import axios from 'axios';\n\nfunction baseUrl() {\n const port = window.location.port === '' ? '' : `:${window.location.port}`;\n\n return `${window.location.protocol}//${window.location.hostname}${port}`;\n}\n\nexport function csrfToken() {\n return document\n .querySelector('meta[name=\"csrf-token\"]')\n .getAttribute('content');\n}\n\nexport default function createNetworkingClient(options = {}) {\n return axios.create({\n baseUrl: baseUrl(),\n /**\n * The Axios timeout was set to 5s, causing requests taking longer than 5s to error out, and therefore causing Sentry errors.\n * Several factors can cause a slow request, such as slow network speeds or server.\n * Bumping the timeout to 30s should help account for these slow requests but also ensure that\n * we are not waiting for request resources for an indefinite time.\n * */\n timeout: 30000, // 30 seconds\n headers: {\n 'X-Requested-With': 'XMLHttpRequest',\n 'X-CSRF-TOKEN': csrfToken()\n },\n ...options\n });\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { logError, logMessage } from './sentry';\n\n// Object that stores references to all the registered components\nlet registeredComponents = {};\n\n// Track a single component that should be mounted after the DOM content has loaded\nfunction register(components) {\n // Registered components are passed in as Hash keys (as opposed to individual arguments)\n // in order to preserve their names during JavaScript minification.\n //\n // For example:\n // ReactComponentMounter.register({ Hello });\n\n registeredComponents = { ...registeredComponents, ...components };\n}\n\nfunction mountComponent({ node, component, props }) {\n const className = component || node.getAttribute('data-react-class');\n const reactComponent = registeredComponents[className];\n\n if (!reactComponent) {\n logMessage(`Cannot find a component registered with the name ${className}`);\n return;\n }\n\n const propsJson = node.getAttribute('data-react-props');\n try {\n const reactProps = {\n ...(propsJson && JSON.parse(propsJson)),\n ...props\n };\n\n const reactElement = React.createElement(reactComponent, reactProps);\n ReactDOM.render(reactElement, node);\n } catch (e) {\n logError(e);\n }\n}\n\n// Allows a page to mount a component right away rather than\n// wait for the DOMContentLoaded event\nfunction inlineMount(node, component) {\n mountComponent({ node, component });\n}\n\n// Search the DOM for all react components to be mounted,\n// and mount them into the DOM\nfunction mountComponents() {\n const nodesToMount = document.querySelectorAll('[data-react-class]');\n // IE does not support NodeList.forEach, so we need to do it the old fashion way\n /* eslint-disable-next-line no-plusplus */\n for (let i = 0; i < nodesToMount.length; ++i) {\n mountComponent({ node: nodesToMount[i] });\n }\n}\n\n// Ensure pages can mount components more specifically\nif (window.stravaInlineMount === undefined) {\n window.stravaInlineMount = inlineMount;\n}\n\n// Add this listener only once, when the module is first imported\ndocument.addEventListener('DOMContentLoaded', mountComponents);\n\n/**\n * Also added once, this listener can be used to render react components\n * that were created after the DOM was loaded via the ruby `react_component` helper\n *\n * example usage:\n *\n * document.dispatchEvent(new CustomEvent('JSCreatedReactNode', {detail: {node: $('#my-react-component')}}))\n * document.dispatchEvent(new CustomEvent('JSCreatedReactNode', {detail: {node: $('#my-react-component')[index]}}))\n */\nfunction mountJSCreatedComponent(e) {\n const { node, component, props } = e.detail;\n if (!node) {\n return;\n }\n\n const unwrappedNode = node.length ? node[0] : node;\n if (!unwrappedNode) {\n return;\n }\n\n mountComponent({ node: unwrappedNode, component, props });\n}\n\ndocument.addEventListener('JSCreatedReactNode', mountJSCreatedComponent);\n\n/**\n * Components mounted using certain erb - jquery setup do not go through their whole\n * lifecyle so they are left unmounted as the athlete interacts on the page.\n *\n * For examples, see interval.js.rb, graph_data_range.js.rb and interval_type.js.rb\n */\ndocument.addEventListener('JSUnmountReactNode', (e) => {\n ReactDOM.unmountComponentAtNode(e.detail.node);\n});\n\nexport default { register, mountComponent };\n","const BROWSER_EXTENSION = '-extension://';\nconst ANONYMOUS = '';\n\n// see https://github.com/thomaschampagne/elevate/blob/fc5772a12327c0d5015fb0fec64aba1cec6756c7/webextension/scripts/processors/activities-synchronize.ts\nconst ELEVATE_APP_CONSOLE_LOGS = [\n 'Fast sync mode enabled',\n 'A previous sync exists on',\n 'local and remote activities count matches',\n 'Mismatch found between local and remote activities. Syncing first page only.',\n 'Activities fetched in group',\n ', raw activities length: ',\n 'PagesRidden] Resolving with ',\n 'clearSyncCache requested',\n 'Group handled count: ',\n 'Updating synced activities to extension local storage.',\n 'Activities fetched in group'\n];\n\nexport const hasExtensionReferenceInHintErrorStack = (hint) =>\n hint?.originalException?.stack?.includes(BROWSER_EXTENSION);\n\nexport const hasExtensionReferenceInBreadCrumbs = (event) =>\n !!event?.breadcrumbs?.find((entry) => {\n return (\n entry.data?.url?.includes(BROWSER_EXTENSION) ||\n ELEVATE_APP_CONSOLE_LOGS.includes(entry.message)\n );\n });\n\nexport const hasExtensionReferenceInEventErrorStack = (event) => {\n return !!event?.exception?.values?.find((entry) => {\n return !!entry.stacktrace?.frames?.find(\n (frame) =>\n frame?.filename?.includes(BROWSER_EXTENSION) ||\n frame?.abs_path?.includes(BROWSER_EXTENSION) ||\n frame?.filename?.includes(ANONYMOUS) ||\n frame?.abs_path?.includes(ANONYMOUS)\n );\n });\n};\n\nexport default {\n hasExtensionReferenceInHintErrorStack,\n hasExtensionReferenceInBreadCrumbs,\n hasExtensionReferenceInEventErrorStack\n};\n","import * as Sentry from '@sentry/browser';\nimport { BrowserTracing } from '@sentry/tracing';\nimport { isDev } from './devUtils';\nimport {\n hasExtensionReferenceInBreadCrumbs,\n hasExtensionReferenceInHintErrorStack,\n hasExtensionReferenceInEventErrorStack\n} from './sentry.helper';\n\n// List of pages that have the same pathname but different variants controlled with\n// search params. Pages added to this list will have the search param added to the name\n// during tracing (performance tracking)\nconst PAGES_WITH_VARIANTS = ['/onboarding/continue', '/'];\n\nif (!window.StravaSentryDsn) {\n window.StravaSentryDsn = {};\n}\nif (!window.StravaSentryDsn.deferred) {\n window.StravaSentryDsn.deferred = {};\n const promise = new Promise(\n function _(resolve, reject) {\n this.doResolve = resolve;\n this.doReject = reject;\n }.bind(window.StravaSentryDsn.deferred)\n );\n window.StravaSentryDsn.deferred.then = promise.then.bind(promise);\n}\n\nconst { enabled, environment, release, userId, dsn, sampleRate, debug } =\n window.StravaSentry || {};\n\nwindow.StravaSentryDsn.deferred.doResolve(dsn);\n\nwindow.StravaSentryDsn.deferred.then((_dsn) => {\n // configure sentry_frontend.yml to enable sentry on local\n if (enabled) {\n Sentry.init({\n dsn: _dsn,\n maxBreadcrumbs: 50,\n integrations: [\n new BrowserTracing({\n tracingOrigins: [\n 'https://www.staging.strava.com',\n 'https://www.strava.com',\n 'localhost',\n /^\\//\n ],\n beforeNavigate: (context) => {\n const { pathname, search } = window.location;\n const includeSearchParam = PAGES_WITH_VARIANTS.includes(pathname);\n return {\n ...context,\n name: includeSearchParam ? pathname.concat(search) : pathname\n };\n }\n })\n ],\n denyUrls: [\n // Chrome extensions\n /extensions\\//i,\n /^chrome:\\/\\//i\n ],\n tracesSampleRate: sampleRate,\n debug,\n attachStacktrace: true,\n release,\n initialScope: {\n user: { id: userId }\n },\n environment,\n beforeSend: (event, hint) => {\n if (\n hasExtensionReferenceInHintErrorStack(hint) ||\n hasExtensionReferenceInBreadCrumbs(event) ||\n hasExtensionReferenceInEventErrorStack(event) ||\n hint?.originalException === 'Timeout' // google-recaptcha flakiness\n ) {\n return null;\n }\n return event;\n }\n });\n }\n});\n\nexport const logError = (err) => {\n if (isDev()) {\n // eslint-disable-next-line no-console\n console.error('logError :::', err);\n return;\n }\n Sentry.captureException(err);\n};\n\nexport const logMessage = (message) => {\n if (isDev()) {\n // eslint-disable-next-line no-console\n console.error('logMessage :::', message);\n return;\n }\n Sentry.captureMessage(message);\n};\n\nexport default { logError, logMessage };\n"],"names":["followAthlete","followerId","followingId","Promise","resolve","createNetworkingClient","post","follow","follower_id","following_id","then","response","status","StatusCodes","data","approved","FOLLOWING_STATUS","catch","bulkFollow","followeeIds","followee_ids","success","ids","followed_athlete_ids","followedAthleteIds","e","logError","unfollowAthlete","delete","headers","Accept","getSuggestedFollows","callsite","reject","get","params","error","remoteUrls","initializedScopes","cleanup","scriptElement","parentNode","removeChild","useDynamicScript","url","React","isLoading","setIsLoading","failed","setFailed","promise","element","document","createElement","src","type","async","onload","onerror","logMessage","head","appendChild","loadDynamicScript","devLog","cleanupScript","DynamicWidget","scope","component","appContext","Component","moduleResolve","react","require","translationscontext","legacyShareScope","version","singleton","loaded","from","containerResolve","window","init","factory","fallback","className","styles","AnalyticsContext","value","track","Strava","ExternalAnalytics","trackV2","TranslationContext","t","key","props","I18n","getLanguage","ErrorLoggingContext","StravaAlert","children","severity","options","clsx","defaultProps","I18nPrefix","InviteFriendsContext","useInviteFriendsContext","displayName","ADD_ALERT","CHANGE_TAB","CLEAR_ALERT","CLEAR_EMAILS","CLOSE_MODAL","OPEN_MODAL","UPDATE_EMAILS","UPDATE_FB_FRIENDS","UPDATE_FB_FRIEND_FOLLOWING_STATUS","UPDATE_INVITED_EMAILS_LIST","clientId","mocked","useState","contacts","setContacts","undefined","token","setToken","AuthorizationStatus","authorizationStatus","setAuthorizationStatus","handleSignInContactsScope","tokenResponse","access_token","accessToken","google","accounts","oauth2","hasGrantedAllScopes","Authorization","PEOPLE_BASE_URL","alt","connections","c","timeout","revoke","useEffect","injectGoogleScript","id","cancel","requestContacts","callback","initTokenClient","client_id","requestAccessToken","disconnect","isNil","dispatch","onClick","action","properties","current_tab","label","getPrimaryEntry","entries","primary","find","entry","metadata","isEmpty","processContactsForUI","processedContacts","map","index","names","emailAddresses","photos","displayContact","isOnStrava","email","name","picture","compact","extractEmailsFromString","emails","split","toLower","trim","contact","FOLLOW_ACTIONS","disabled","config","setConfig","followingStatus","currentFollowingStatus","setCurrentFollowingStatus","state","currentAthlete","invitedEmailsList","approveFollowers","includes","prev","disabledTextStyle","Avatar","size","badge","Button","variant","athlete_id","separator","payload","concat","alert","message","finally","handleBtnClick","ResultsFeed","results","Spinner","length","searchKeyword","setSearchKeyword","filterResults","setFilterResults","initialResults","useRef","current","contacts_count","already_on_strava_count","filter","onChange","keyword","target","toLowerCase","placeholder","safeDispatch","useSafeDispatch","googleClientId","useGoogle","useSafeState","setProcessedContacts","isProcessingContacts","setIsProcessingContacts","isSendingEmails","setIsSendingEmails","emailInputRef","emailMessage","dispatchAlert","useCallback","uniqBy","remove","importedEmails","forEach","friend","approve_followers","following_status","display_name","orderBy","focus","alreadyOnStravaMessage","alreadyOnStrava","numOnStrava","email_address","escape","other_email_address","count","isValidEmailList","emailList","EmailValidator","handleFormSubmission","event","preventDefault","email_count","is_valid_email_list","toString","i","to","body","invite_dialog","sent","notSent","not_sent","already_on_strava","noWrap","content","onSubmit","htmlFor","ref","isModalOpen","modalTabIndex","fbAppId","fbVersion","locale","ModalWithTabs","isOpen","onDismiss","title","selectedTab","FindFacebookFriends","source","INVITE_FRIENDS","fbApiProps","appId","isVisible","reducer","fbFriends","isFollowable","Error","InviteFriendsButton","defaultTabIndex","useInView","threshold","intersectionObserverRef","inView","fields","page","category","default_tab","useReducer","providerState","useMemo","cta","logo","cx","camelCase","Permissions","Object","freeze","FRIEND_LIST","autoSync","setFbFriends","isInitialRequest","setIsInitialRequest","injectFacebookScript","checkPermissions","grantedScopes","requestedScopes","difference","getGrantedScopes","p","permission","requestPermissions","FB","getLoginStatus","authResponse","isDev","module","default","stravaFbProxyPostPermissions","hasPermissions","return_scopes","auth_type","login","grantedScopesList","fbGraphApiLogin","requestFriends","stravaFbProxyPostFriends","fbData","facebookUIDs","facebook_uids","stravaUsersFromFbIds","stravaData","camelCaseFriends","athlete","subtitle","display_location","LinkFacebookButton","fullWidth","LogosFacebookSmall","useFriendsContext","isInviteFriends","analyticsBySource","authorization_status","sortedFriends","isProcessing","setIsProcessing","handleFollowAll","friends","UPDATE_FRIEND_FOLLOWING_STATUS","follow_all_count","follow_all_status","some","sortBy","values","friendCount","onboardingFriendCountMessage","friend_count","initialScreenEnter","analytics","friends_count","ONBOARDING","FriendList","FriendListItem","onFollowingFriendsChange","followedFriends","useFacebook","processedFriends","fromEntries","sortedIndex","UPDATE_FRIENDS","FriendsContext","isMobile","style","flexShrink","setCta","useCtaAction","SUGGESTED_FRIENDS","ADD_ATHLETE","REMOVE_ATHLETE","createContext","context","useContext","rest","ALERT_TYPES","warning","info","following","pending","canFollow","canRequest","add","followRequested","requestToFollow","appendScriptToBody","script","querySelector","injectAppleScript","apple","formattedLocale","replace","fbAsyncInit","xfbml","cookie","AUTHORIZED","DATA_FETCHED","ERROR","INITIATED","READY","REQUEST_PERMISSIONS","REQUEST_NEW_PERMISSIONS","UNAUTHORIZED","FormattedHTMLMessage","tagName","onLinkClick","dangerouslySetInnerHTML","__html","nodeName","Locale","t_html","elevationFormatter","unitSystem","ElevationFormatter","elevationLabelFormatter","ChartLabelElevationFormatter","distanceFormatter","DistanceFormatter","distanceLabelFormatter","ChartLabelDistanceFormatter","distancePerTimeFormatter","DistancePerTimeFormatter","distancePerTimeLabelFormatter","ChartLabelDistancePerTimeFormatter","percentFormatter","PercentFormatter","timespanFormatter","TimespanFormatter","language","Locales","LANGUAGE_CODE","measurementUnits","UnitSystem","process","string","StravaDevTools","enabled","console","log","ms","setTimeout","generateRandomId","Math","random","substring","titleize","str","txt","charAt","toUpperCase","substr","firstName","lastName","forceAnonymize","maxLength","fullName","navigator","userAgent","dateYearsAgo","years","d","Date","toDateString","setFullYear","getFullYear","parseServerDateString","date","dobArray","year","parseInt","month","day","csrfToken","getAttribute","axios","baseUrl","port","location","protocol","hostname","registeredComponents","mountComponent","node","reactComponent","propsJson","reactProps","JSON","parse","reactElement","ReactDOM","stravaInlineMount","addEventListener","nodesToMount","querySelectorAll","detail","unwrappedNode","register","components","BROWSER_EXTENSION","ANONYMOUS","ELEVATE_APP_CONSOLE_LOGS","hasExtensionReferenceInHintErrorStack","hint","originalException","stack","hasExtensionReferenceInBreadCrumbs","breadcrumbs","hasExtensionReferenceInEventErrorStack","exception","stacktrace","frames","frame","filename","abs_path","PAGES_WITH_VARIANTS","StravaSentryDsn","deferred","this","doResolve","doReject","bind","StravaSentry","environment","release","userId","dsn","sampleRate","debug","_dsn","Sentry","maxBreadcrumbs","integrations","BrowserTracing","tracingOrigins","beforeNavigate","pathname","search","includeSearchParam","denyUrls","tracesSampleRate","attachStacktrace","initialScope","user","beforeSend","err"],"sourceRoot":""}