diff --git a/lib/utils/push-alerts.js b/lib/utils/push-alerts.js --- a/lib/utils/push-alerts.js +++ b/lib/utils/push-alerts.js @@ -1,14 +1,30 @@ // @flow import type { AlertInfo } from '../types/alert-types.js'; +import { isDev } from '../utils/dev-utils.js'; +import { usingCommServicesAccessToken } from '../utils/services-utils.js'; const msInDay = 24 * 60 * 60 * 1000; -const shouldSkipPushPermissionAlert = (alertInfo: AlertInfo): boolean => - (alertInfo.totalAlerts > 3 && - alertInfo.lastAlertTime > Date.now() - msInDay) || - (alertInfo.totalAlerts > 6 && - alertInfo.lastAlertTime > Date.now() - msInDay * 3) || - (alertInfo.totalAlerts > 9 && - alertInfo.lastAlertTime > Date.now() - msInDay * 7); - -export { shouldSkipPushPermissionAlert }; + +function shouldSkipPushPermissionAlert(alertInfo: AlertInfo): boolean { + return ( + (alertInfo.totalAlerts > 3 && + alertInfo.lastAlertTime > Date.now() - msInDay) || + (alertInfo.totalAlerts > 6 && + alertInfo.lastAlertTime > Date.now() - msInDay * 3) || + (alertInfo.totalAlerts > 9 && + alertInfo.lastAlertTime > Date.now() - msInDay * 7) + ); +} + +function shouldSkipConnectFarcasterAlert(alertInfo: AlertInfo): boolean { + // The isDev check is here so that devs don't get continually spammed + // with this alert. + return ( + isDev || + !usingCommServicesAccessToken || + alertInfo.lastAlertTime > Date.now() - msInDay + ); +} + +export { shouldSkipPushPermissionAlert, shouldSkipConnectFarcasterAlert }; diff --git a/native/components/farcaster-handler.react.js b/native/components/farcaster-handler.react.js new file mode 100644 --- /dev/null +++ b/native/components/farcaster-handler.react.js @@ -0,0 +1,70 @@ +// @flow + +import { useNavigation } from '@react-navigation/native'; +import * as React from 'react'; + +import { recordAlertActionType } from 'lib/actions/alert-actions.js'; +import { FarcasterDataHandler } from 'lib/components/farcaster-data-handler.react.js'; +import { FIDContext } from 'lib/components/fid-provider.react.js'; +import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + alertTypes, + type RecordAlertActionPayload, +} from 'lib/types/alert-types.js'; +import { authoritativeKeyserverID } from 'lib/utils/authoritative-keyserver.js'; +import { shouldSkipConnectFarcasterAlert } from 'lib/utils/push-alerts.js'; +import { useDispatch } from 'lib/utils/redux-utils.js'; +import sleep from 'lib/utils/sleep.js'; + +import { ConnectFarcasterBottomSheetRouteName } from '../navigation/route-names.js'; +import { useSelector } from '../redux/redux-utils.js'; + +function FacasterHandler(): React.Node { + const { navigate } = useNavigation(); + + const isActive = useSelector(state => state.lifecycleState !== 'background'); + + const currentUserID = useSelector(state => state.currentUserInfo?.id); + const cookie = useSelector(cookieSelector(authoritativeKeyserverID())); + const hasUserCookie = !!(cookie && cookie.startsWith('user=')); + const loggedIn = !!currentUserID && hasUserCookie; + + const fid = React.useContext(FIDContext)?.fid; + + const connectFarcasterAlertInfo = useSelector( + state => state.alertStore.alertInfos[alertTypes.CONNECT_FARCASTER], + ); + + const dispatch = useDispatch(); + + React.useEffect(() => { + if ( + !loggedIn || + !isActive || + !!fid || + shouldSkipConnectFarcasterAlert(connectFarcasterAlertInfo) + ) { + return; + } + + void (async () => { + await sleep(1000); + + navigate(ConnectFarcasterBottomSheetRouteName); + + const payload: RecordAlertActionPayload = { + alertType: alertTypes.CONNECT_FARCASTER, + time: Date.now(), + }; + + dispatch({ + type: recordAlertActionType, + payload, + }); + })(); + }, [connectFarcasterAlertInfo, dispatch, fid, isActive, loggedIn, navigate]); + + return ; +} + +export default FacasterHandler; diff --git a/native/root.react.js b/native/root.react.js --- a/native/root.react.js +++ b/native/root.react.js @@ -26,7 +26,6 @@ import { ChatMentionContextProvider } from 'lib/components/chat-mention-provider.react.js'; import { EditUserAvatarProvider } from 'lib/components/edit-user-avatar-provider.react.js'; import { ENSCacheProvider } from 'lib/components/ens-cache-provider.react.js'; -import { FarcasterDataHandler } from 'lib/components/farcaster-data-handler.react.js'; import { FIDProvider } from 'lib/components/fid-provider.react.js'; import IntegrityHandler from 'lib/components/integrity-handler.react.js'; import KeyserverConnectionsHandler from 'lib/components/keyserver-connections-handler.js'; @@ -47,6 +46,7 @@ import ChatContextProvider from './chat/chat-context-provider.react.js'; import MessageEditingContextProvider from './chat/message-editing-context-provider.react.js'; import AccessTokenHandler from './components/access-token-handler.react.js'; +import FarcasterHandler from './components/farcaster-handler.react.js'; import { FeatureFlagsProvider } from './components/feature-flags-provider.react.js'; import PersistedStateGate from './components/persisted-state-gate.js'; import ReportHandler from './components/report-handler.react.js'; @@ -298,6 +298,7 @@ + ); @@ -344,7 +345,6 @@ - {navigation}