diff --git a/apps/web/jest.config.js b/apps/web/jest.config.js index f4c80ee73d..d461db8265 100644 --- a/apps/web/jest.config.js +++ b/apps/web/jest.config.js @@ -44,6 +44,7 @@ module.exports = async () => { 'preact', 'uint8arrays', 'multiformats', + '@farcaster/auth-kit', ]; return { diff --git a/apps/web/src/components/Feed/Socialize/AdmireButton.tsx b/apps/web/src/components/Feed/Socialize/AdmireButton.tsx index 75bd73da5c..4563b0272c 100644 --- a/apps/web/src/components/Feed/Socialize/AdmireButton.tsx +++ b/apps/web/src/components/Feed/Socialize/AdmireButton.tsx @@ -2,10 +2,9 @@ import { useCallback } from 'react'; import { useFragment } from 'react-relay'; import { graphql } from 'relay-runtime'; -import { useModalActions } from '~/contexts/modal/ModalContext'; import { AdmireButtonFragment$key } from '~/generated/AdmireButtonFragment.graphql'; import { AdmireButtonQueryFragment$key } from '~/generated/AdmireButtonQueryFragment.graphql'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { AdmireIcon } from '~/icons/SocializeIcons'; import { contexts } from '~/shared/analytics/constants'; import { useTrack } from '~/shared/contexts/AnalyticsContext'; @@ -53,13 +52,11 @@ export function AdmireButton({ eventRef, queryRef, onAdmire, onRemoveAdmire }: A viewer { __typename } - - ...useAuthModalFragment } `, queryRef ); - const { showModal } = useModalActions(); + const showAuthModal = useUniversalAuthModal(); const track = useTrack(); @@ -78,16 +75,12 @@ export function AdmireButton({ eventRef, queryRef, onAdmire, onRemoveAdmire }: A }); if (query.viewer?.__typename !== 'Viewer') { - showModal({ - content: , - headerText: 'Sign In', - }); - + showAuthModal(); return; } onAdmire(); - }, [query, track, onAdmire, showModal]); + }, [track, query.viewer?.__typename, onAdmire, showAuthModal]); const hasViewerAdmiredEvent = Boolean(feedItem.viewerAdmire); diff --git a/apps/web/src/components/Feed/Socialize/AdmireLine.tsx b/apps/web/src/components/Feed/Socialize/AdmireLine.tsx index acc1f7658e..b222aa41ba 100644 --- a/apps/web/src/components/Feed/Socialize/AdmireLine.tsx +++ b/apps/web/src/components/Feed/Socialize/AdmireLine.tsx @@ -6,10 +6,9 @@ import styled from 'styled-components'; import { HStack } from '~/components/core/Spacer/Stack'; import { BaseM, TitleDiatypeM } from '~/components/core/Text/Text'; import { ProfilePictureStack } from '~/components/ProfilePicture/ProfilePictureStack'; -import { useModalActions } from '~/contexts/modal/ModalContext'; import { AdmireLineFragment$key } from '~/generated/AdmireLineFragment.graphql'; import { AdmireLineQueryFragment$key } from '~/generated/AdmireLineQueryFragment.graphql'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { useTrack } from '~/shared/contexts/AnalyticsContext'; import { removeNullValues } from '~/shared/relay/removeNullValues'; @@ -82,7 +81,6 @@ export function AdmireLine({ eventRef, queryRef, onAdmire }: CommentLineProps) { } } ...useAdmireModalQueryFragment - ...useAuthModalFragment } `, queryRef @@ -126,22 +124,18 @@ export function AdmireLine({ eventRef, queryRef, onAdmire }: CommentLineProps) { const totalAdmires = event.previewAdmires?.pageInfo.total ?? 0; - const { showModal } = useModalActions(); + const showAuthModal = useUniversalAuthModal(); const track = useTrack(); const handleAdmire = useCallback(async () => { if (query.viewer?.__typename !== 'Viewer') { - showModal({ - content: , - headerText: 'Sign In', - }); - + showAuthModal(); return; } track('Admire Click'); onAdmire(); - }, [onAdmire, query, showModal, track]); + }, [onAdmire, query.viewer?.__typename, showAuthModal, track]); if (totalAdmires === 0) { return ( diff --git a/apps/web/src/components/Feed/Socialize/CommentBox/CommentBox.tsx b/apps/web/src/components/Feed/Socialize/CommentBox/CommentBox.tsx index 482e4158d2..eca9fb0c33 100644 --- a/apps/web/src/components/Feed/Socialize/CommentBox/CommentBox.tsx +++ b/apps/web/src/components/Feed/Socialize/CommentBox/CommentBox.tsx @@ -17,11 +17,10 @@ import { BaseM, BODY_FONT_FAMILY } from '~/components/core/Text/Text'; import { SendButton } from '~/components/Feed/Socialize/SendButton'; import { FloatingCard } from '~/components/Mention/FloatingCard'; import { MentionModal } from '~/components/Mention/MentionModal'; -import { useModalActions } from '~/contexts/modal/ModalContext'; import { useToastActions } from '~/contexts/toast/ToastContext'; import { CommentBoxQueryFragment$key } from '~/generated/CommentBoxQueryFragment.graphql'; import { MentionInput } from '~/generated/useCommentOnPostMutation.graphql'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { contexts } from '~/shared/analytics/constants'; import { useTrack } from '~/shared/contexts/AnalyticsContext'; import { MentionType, useMentionableMessage } from '~/shared/hooks/useMentionableMessage'; @@ -45,7 +44,6 @@ export function CommentBox({ queryRef, onSubmitComment, isSubmittingComment, rep viewer { __typename } - ...useAuthModalFragment } `, queryRef @@ -80,7 +78,7 @@ export function CommentBox({ queryRef, onSubmitComment, isSubmittingComment, rep const { pushToast } = useToastActions(); const track = useTrack(); - const { showModal } = useModalActions(); + const showAuthModal = useUniversalAuthModal(); useEffect(() => { textareaRef.current?.focus(); @@ -105,11 +103,7 @@ export function CommentBox({ queryRef, onSubmitComment, isSubmittingComment, rep const handleSubmit = useCallback(async () => { if (query.viewer?.__typename !== 'Viewer') { - showModal({ - content: , - headerText: 'Sign In', - }); - + showAuthModal(); return; } @@ -131,16 +125,16 @@ export function CommentBox({ queryRef, onSubmitComment, isSubmittingComment, rep } resetInputState(); }, [ - query, + query.viewer?.__typename, isSubmittingComment, - mentions, message, track, resetInputState, - showModal, + showAuthModal, onSubmitComment, - pushErrorToast, + mentions, replyToId, + pushErrorToast, ]); const handleInputKeyDown = useCallback( diff --git a/apps/web/src/components/Follow/FollowButton.tsx b/apps/web/src/components/Follow/FollowButton.tsx index c5ddc49550..faecc91cfd 100644 --- a/apps/web/src/components/Follow/FollowButton.tsx +++ b/apps/web/src/components/Follow/FollowButton.tsx @@ -6,7 +6,7 @@ import { HStack } from '~/components/core/Spacer/Stack'; import { useToastActions } from '~/contexts/toast/ToastContext'; import { FollowButtonQueryFragment$key } from '~/generated/FollowButtonQueryFragment.graphql'; import { FollowButtonUserFragment$key } from '~/generated/FollowButtonUserFragment.graphql'; -import useAuthModal from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { contexts } from '~/shared/analytics/constants'; import { useTrack } from '~/shared/contexts/AnalyticsContext'; import useFollowUser from '~/shared/relay/useFollowUser'; @@ -118,7 +118,7 @@ export default function FollowButton({ const followUser = useFollowUser({ queryRef: loggedInUserQuery }); const unfollowUser = useUnfollowUser({ queryRef: loggedInUserQuery }); const { pushToast } = useToastActions(); - const showAuthModal = useAuthModal('sign-in'); + const showAuthModal = useUniversalAuthModal(); const track = useTrack(); const [hasClickedFollowAndIsHovering, setHasClickedFollowAndIsHovering] = useState(false); diff --git a/apps/web/src/components/NftPreview/NftPreviewBookmarkLabel.tsx b/apps/web/src/components/NftPreview/NftPreviewBookmarkLabel.tsx index f31699a6c7..153b60162d 100644 --- a/apps/web/src/components/NftPreview/NftPreviewBookmarkLabel.tsx +++ b/apps/web/src/components/NftPreview/NftPreviewBookmarkLabel.tsx @@ -5,12 +5,11 @@ import { useTrack } from 'shared/contexts/AnalyticsContext'; import colors from 'shared/theme/colors'; import styled from 'styled-components'; -import { useModalActions } from '~/contexts/modal/ModalContext'; import { NftPreviewBookmarkLabelFragment$key } from '~/generated/NftPreviewBookmarkLabelFragment.graphql'; import { NftPreviewBookmarkLabelQueryFragment$key } from '~/generated/NftPreviewBookmarkLabelQueryFragment.graphql'; import useAdmireToken from '~/hooks/api/posts/useAdmireToken'; import useRemoveTokenAdmire from '~/hooks/api/posts/useRemoveTokenAdmire'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import BookmarkIcon from '~/icons/BookmarkIcon'; import unescape from '~/shared/utils/unescape'; import useOptimisticUserInfo from '~/utils/useOptimisticUserInfo'; @@ -52,7 +51,6 @@ export default function NftPreviewBookmarkLabel({ tokenRef, queryRef }: Props) { } } ...useOptimisticUserInfoFragment - ...useAuthModalFragment } `, queryRef @@ -73,20 +71,16 @@ export default function NftPreviewBookmarkLabel({ tokenRef, queryRef }: Props) { return null; }, [token.definition.name]); - const { showModal } = useModalActions(); - const [admireToken] = useAdmireToken(); const [removeTokenAdmire] = useRemoveTokenAdmire(); const track = useTrack(); const { route } = useRouter(); + const showAuthModal = useUniversalAuthModal(); + const handleAddBookmark = useCallback(() => { if (query.viewer?.__typename !== 'Viewer') { - showModal({ - content: , - headerText: 'Sign In', - }); - + showAuthModal(); return; } @@ -97,7 +91,17 @@ export default function NftPreviewBookmarkLabel({ tokenRef, queryRef }: Props) { }); admireToken(token.id, token.dbid, info, decodedTokenName); - }, [admireToken, decodedTokenName, info, query, route, showModal, token.dbid, token.id, track]); + }, [ + admireToken, + decodedTokenName, + info, + query.viewer?.__typename, + route, + showAuthModal, + token.dbid, + token.id, + track, + ]); const handleRemoveBookmark = useCallback(() => { if ( diff --git a/apps/web/src/contexts/globalLayout/GlobalAnnouncementPopover/GlobalAnnouncementPopover.tsx b/apps/web/src/contexts/globalLayout/GlobalAnnouncementPopover/GlobalAnnouncementPopover.tsx index c7dc78525c..310fb7fe61 100644 --- a/apps/web/src/contexts/globalLayout/GlobalAnnouncementPopover/GlobalAnnouncementPopover.tsx +++ b/apps/web/src/contexts/globalLayout/GlobalAnnouncementPopover/GlobalAnnouncementPopover.tsx @@ -11,7 +11,7 @@ import { HStack, VStack } from '~/components/core/Spacer/Stack'; import { BaseM, BODY_FONT_FAMILY } from '~/components/core/Text/Text'; import { useModalActions } from '~/contexts/modal/ModalContext'; import { GlobalAnnouncementPopoverFragment$key } from '~/generated/GlobalAnnouncementPopoverFragment.graphql'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { useIsDesktopWindowWidth } from '~/hooks/useWindowSize'; import { contexts } from '~/shared/analytics/constants'; import colors from '~/shared/theme/colors'; @@ -59,7 +59,6 @@ export default function GlobalAnnouncementPopover({ queryRef }: Props) { ...FeaturedCollectorCardCollectionFragment } } - ...useAuthModalFragment ...FeaturedCollectorCardFragment } `, @@ -70,7 +69,8 @@ export default function GlobalAnnouncementPopover({ queryRef }: Props) { throw new Error('GlobalAnnouncementPopver did not receive gallery of the week winners'); } - const { showModal, hideModal } = useModalActions(); + const { hideModal } = useModalActions(); + const showAuthModal = useUniversalAuthModal(); const isMobile = !useIsDesktopWindowWidth(); @@ -86,11 +86,8 @@ export default function GlobalAnnouncementPopover({ queryRef }: Props) { return; } - showModal({ - content: , - headerText: 'Create account', - }); - }, [hideModal, isAuthenticated, push, query, showModal]); + showAuthModal(); + }, [hideModal, isAuthenticated, push, showAuthModal]); const handleSecondaryButtonClick = useCallback(() => { document.getElementById('beautiful-home')?.scrollIntoView({ behavior: 'smooth' }); diff --git a/apps/web/src/contexts/globalLayout/GlobalNavbar/SignUpButton.tsx b/apps/web/src/contexts/globalLayout/GlobalNavbar/SignUpButton.tsx index b2572ce428..dec53bdb10 100644 --- a/apps/web/src/contexts/globalLayout/GlobalNavbar/SignUpButton.tsx +++ b/apps/web/src/contexts/globalLayout/GlobalNavbar/SignUpButton.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { Button } from '~/components/core/Button/Button'; import { TitleDiatypeL } from '~/components/core/Text/Text'; -import useAuthModal from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { contexts, flows } from '~/shared/analytics/constants'; type Props = { @@ -12,7 +12,7 @@ type Props = { }; export function SignUpButton({ className, buttonLocation }: Props) { - const showAuthModal = useAuthModal('sign-up'); + const showAuthModal = useUniversalAuthModal(); return ( { // Only show the modal if the user is logged in and the settings query param is set diff --git a/apps/web/src/hooks/useAuthModal.tsx b/apps/web/src/hooks/useAuthModal.tsx deleted file mode 100644 index c18b81bc6d..0000000000 --- a/apps/web/src/hooks/useAuthModal.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useCallback } from 'react'; -import { graphql, useFragment, useLazyLoadQuery } from 'react-relay'; -import styled from 'styled-components'; - -import { VStack } from '~/components/core/Spacer/Stack'; -import { WalletSelectorVariant } from '~/components/WalletSelector/multichain/MultichainWalletSelector'; -import WalletSelector from '~/components/WalletSelector/WalletSelector'; -import { useModalActions } from '~/contexts/modal/ModalContext'; -import { useAuthModalFragment$key } from '~/generated/useAuthModalFragment.graphql'; -import { useAuthModalQuery } from '~/generated/useAuthModalQuery.graphql'; - -type ModalProps = { - queryRef: useAuthModalFragment$key; -}; - -export const AuthModal = ({ queryRef }: ModalProps) => { - const query = useFragment( - graphql` - fragment useAuthModalFragment on Query { - ...WalletSelectorFragment - } - `, - queryRef - ); - - return ( - - - - ); -}; - -const Container = styled(VStack)` - display: flex; - justify-content: center; - - // the height of the inner content with all wallet options listed. - // ensures the height of the modal doesn't shift - min-height: 320px; - height: 100%; -`; - -export default function useAuthModal(variant: WalletSelectorVariant) { - const { showModal } = useModalActions(); - - const query = useLazyLoadQuery( - graphql` - query useAuthModalQuery { - ...useAuthModalFragment - } - `, - {} - ); - - return useCallback(() => { - showModal({ - id: 'auth', - content: , - headerText: variant === 'sign-up' ? 'Sign Up' : 'Sign In', - }); - }, [query, variant, showModal]); -} diff --git a/apps/web/src/scenes/LandingPage/LandingPage.tsx b/apps/web/src/scenes/LandingPage/LandingPage.tsx index 6b1c087c8e..c79b42606e 100644 --- a/apps/web/src/scenes/LandingPage/LandingPage.tsx +++ b/apps/web/src/scenes/LandingPage/LandingPage.tsx @@ -8,7 +8,7 @@ import { Button } from '~/components/core/Button/Button'; import { HStack, VStack } from '~/components/core/Spacer/Stack'; import { BaseXL, TitleDiatypeL, TitleXS } from '~/components/core/Text/Text'; import { useModalActions } from '~/contexts/modal/ModalContext'; -import useAuthModal from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { useIsDesktopWindowWidth, useIsMobileOrMobileLargeWindowWidth, @@ -33,7 +33,7 @@ type Props = { export default function LandingPage({ pageContent }: Props) { const isMobile = useIsMobileOrMobileLargeWindowWidth(); const isDesktop = useIsDesktopWindowWidth(); - const showAuthModal = useAuthModal('sign-up'); + const showAuthModal = useUniversalAuthModal(); const { showModal } = useModalActions(); const handleDownloadAppClick = useCallback(() => { diff --git a/apps/web/src/scenes/MerchStorePage/MerchStorePage.tsx b/apps/web/src/scenes/MerchStorePage/MerchStorePage.tsx index 8f74d8033d..004dc6a25d 100644 --- a/apps/web/src/scenes/MerchStorePage/MerchStorePage.tsx +++ b/apps/web/src/scenes/MerchStorePage/MerchStorePage.tsx @@ -10,7 +10,7 @@ import { TitleM, TitleMonoM } from '~/components/core/Text/Text'; import { GLOBAL_FOOTER_HEIGHT } from '~/contexts/globalLayout/GlobalFooter/GlobalFooter'; import { MerchStorePageQuery } from '~/generated/MerchStorePageQuery.graphql'; import { MerchStorePageQueryFragment$key } from '~/generated/MerchStorePageQueryFragment.graphql'; -import useAuthModal from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import LogoBracketLeft from '~/icons/LogoBracketLeft'; import LogoBracketRight from '~/icons/LogoBracketRight'; import { contexts } from '~/shared/analytics/constants'; @@ -100,7 +100,7 @@ export default function MerchStorePage({ queryRef }: Props) { ); const { merchTokens } = query; - const showAuthModal = useAuthModal('sign-in'); + const showAuthModal = useUniversalAuthModal(); const showRedeemModal = useRedeemModal(merchTokens); const loggedInUserId = useLoggedInUserId(userQuery); diff --git a/apps/web/src/scenes/NftDetailPage/NftDetailAsset.test.tsx b/apps/web/src/scenes/NftDetailPage/NftDetailAsset.test.tsx index afa6966dbf..945d2b2e4d 100644 --- a/apps/web/src/scenes/NftDetailPage/NftDetailAsset.test.tsx +++ b/apps/web/src/scenes/NftDetailPage/NftDetailAsset.test.tsx @@ -243,7 +243,6 @@ const UnknownMediaResponse: NftDetailAssetTestQueryQuery = { profileImage: { __typename: 'EnsProfileImage', }, - wallets: [], }, }, }; diff --git a/apps/web/src/scenes/NftDetailPage/NftDetailText.tsx b/apps/web/src/scenes/NftDetailPage/NftDetailText.tsx index b1209b410f..2d2c4fbfed 100644 --- a/apps/web/src/scenes/NftDetailPage/NftDetailText.tsx +++ b/apps/web/src/scenes/NftDetailPage/NftDetailText.tsx @@ -24,7 +24,7 @@ import { NftDetailTextFragment$key } from '~/generated/NftDetailTextFragment.gra import { NftDetailTextQueryFragment$key } from '~/generated/NftDetailTextQueryFragment.graphql'; import useAdmireToken from '~/hooks/api/posts/useAdmireToken'; import useRemoveTokenAdmire from '~/hooks/api/posts/useRemoveTokenAdmire'; -import { AuthModal } from '~/hooks/useAuthModal'; +import useUniversalAuthModal from '~/hooks/useUniversalAuthModal'; import { useBreakpoint, useIsMobileWindowWidth } from '~/hooks/useWindowSize'; import BookmarkIcon from '~/icons/BookmarkIcon'; import ExpandIcon from '~/icons/ExpandIcon'; @@ -108,7 +108,6 @@ function NftDetailText({ queryRef, tokenRef, authenticatedUserOwnsAsset, toggleL } } ...useOptimisticUserInfoFragment - ...useAuthModalFragment } `, queryRef @@ -136,19 +135,26 @@ function NftDetailText({ queryRef, tokenRef, authenticatedUserOwnsAsset, toggleL const [admireToken] = useAdmireToken(); const [removeTokenAdmire] = useRemoveTokenAdmire(); + const showAuthModal = useUniversalAuthModal(); + const handleAdmire = useCallback(async () => { if (query.viewer?.__typename !== 'Viewer') { - showModal({ - content: , - headerText: 'Sign In', - }); - + showAuthModal(); return; } track('Admire Token Click'); admireToken(token.id, token.dbid, info, decodedTokenName); - }, [query, track, admireToken, token.id, token.dbid, info, decodedTokenName, showModal]); + }, [ + query.viewer?.__typename, + track, + admireToken, + token.id, + token.dbid, + info, + decodedTokenName, + showAuthModal, + ]); const handleRemoveAdmire = useCallback(async () => { if (