Skip to content

Commit

Permalink
Add login functionality before doing tx if without anon login
Browse files Browse the repository at this point in the history
  • Loading branch information
teodorus-nathaniel committed Nov 27, 2023
1 parent 7ad7a21 commit b8f468b
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 27 deletions.
11 changes: 2 additions & 9 deletions src/components/auth/LoginModal/LoginModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,17 @@ import MenuList from '@/components/MenuList'
import { ModalFunctionalityProps } from '@/components/modals/Modal'
import ProfilePreview from '@/components/ProfilePreview'
import Toast from '@/components/Toast'
import { getChatIdsWithoutAnonLoginOptions } from '@/constants/chat'
import useLoginAndRequestToken from '@/hooks/useLoginAndRequestToken'
import useSignMessageAndLinkEvmAddress from '@/hooks/useSignMessageAndLinkEvmAddress'
import useToastError from '@/hooks/useToastError'
import useWithoutAnonLoginOptions from '@/hooks/useWithoutAnonLoginOptions'
import { ApiRequestTokenResponse } from '@/pages/api/request-token'
import { useRequestToken } from '@/services/api/mutation'
import { useSendEvent } from '@/stores/analytics'
import { useMyAccount, useMyMainAddress } from '@/stores/my-account'
import { useProfileModal } from '@/stores/profile-modal'
import { cx } from '@/utils/class-names'
import { getIdFromSlug } from '@/utils/slug'
import Image from 'next/image'
import { useRouter } from 'next/router'
import {
Dispatch,
SetStateAction,
Expand Down Expand Up @@ -73,9 +71,7 @@ export const LoginContent = ({
}: ContentProps) => {
const [hasStartCaptcha, setHasStartCaptcha] = useState(false)
const sendEvent = useSendEvent()
const { query } = useRouter()
const chatId =
typeof query.slug === 'string' ? getIdFromSlug(query.slug) : undefined
const withoutAnonLoginOptions = useWithoutAnonLoginOptions()

const {
mutateAsync: loginAndRequestToken,
Expand All @@ -89,9 +85,6 @@ export const LoginContent = ({
)

const isLoading = loadingRequestToken || hasStartCaptcha
const withoutAnonLoginOptions = getChatIdsWithoutAnonLoginOptions().includes(
chatId ?? ''
)

return (
<div>
Expand Down
6 changes: 4 additions & 2 deletions src/components/chats/ChatForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ERRORS } from '@/constants/error'
import useAutofocus from '@/hooks/useAutofocus'
import useRequestTokenAndSendMessage from '@/hooks/useRequestTokenAndSendMessage'
import { showErrorToast } from '@/hooks/useToastError'
import useWithoutAnonLoginOptions from '@/hooks/useWithoutAnonLoginOptions'
import { useConfigContext } from '@/providers/ConfigProvider'
import { getPostQuery } from '@/services/api/query'
import {
Expand Down Expand Up @@ -91,6 +92,7 @@ export default function ChatForm({
const messageToEdit = useMessageData((state) => state.messageToEdit)
const clearAction = useMessageData((state) => state.clearAction)
const setMessageBody = useMessageData((state) => state.setMessageBody)
const { withoutAnonLoginOptions } = useWithoutAnonLoginOptions()

const { data: editedMessage } = getPostQuery.useQuery(messageToEdit, {
enabled: !!messageToEdit,
Expand Down Expand Up @@ -188,6 +190,7 @@ export default function ChatForm({
clearAction?.()
}

const needCaptcha = !shouldSendMessage && !withoutAnonLoginOptions
const handleSubmit = async (captchaToken: string | null) => {
if (
shouldSendMessage &&
Expand Down Expand Up @@ -244,7 +247,6 @@ export default function ChatForm({
resetForm()
sendMessage(messageParams)
} else {
if (!captchaToken) return
resetForm()
requestTokenAndSendMessage({
captchaToken,
Expand Down Expand Up @@ -274,7 +276,7 @@ export default function ChatForm({
{(runCaptcha) => {
const submitForm = async (e?: SyntheticEvent) => {
e?.preventDefault()
if (shouldSendMessage) {
if (!needCaptcha) {
handleSubmit(null)
return
}
Expand Down
10 changes: 6 additions & 4 deletions src/components/navbar/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import usePrevious from '@/hooks/usePrevious'
import { useConfigContext } from '@/providers/ConfigProvider'
import { getUnreadCountQuery } from '@/services/subsocial/datahub/posts/query'
import { useSendEvent } from '@/stores/analytics'
import { useLoginModal } from '@/stores/login-modal'
import { useMyAccount, useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { getDatahubConfig } from '@/utils/env/client'
Expand Down Expand Up @@ -58,7 +59,8 @@ export default function Navbar({
const prevAddress = usePrevious(address)
const isLoggedIn = !!address

const [openLoginModal, setOpenLoginModal] = useState(false)
const isOpen = useLoginModal((state) => state.isOpen)
const setIsOpen = useLoginModal((state) => state.setIsOpen)
const [openPrivateKeyNotice, setOpenPrivateKeyNotice] = useState(false)
const isLoggingInWithKey = useRef(false)
const timeoutRef = useRef<any>()
Expand All @@ -79,7 +81,7 @@ export default function Navbar({
}, [address, isInitializedAddress, prevAddress])

const login = () => {
setOpenLoginModal(true)
setIsOpen(true)
}

const renderAuthComponent = () => {
Expand Down Expand Up @@ -154,8 +156,8 @@ export default function Navbar({
</Container>
</nav>
<LoginModal
isOpen={openLoginModal}
closeModal={() => setOpenLoginModal(false)}
isOpen={isOpen}
closeModal={() => setIsOpen(false)}
beforeLogin={() => (isLoggingInWithKey.current = true)}
afterLogin={() => (isLoggingInWithKey.current = false)}
/>
Expand Down
27 changes: 19 additions & 8 deletions src/hooks/useRequestTokenAndSendMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import {
} from '@/services/subsocial/commentIds'
import { useMyAccount, useMyMainAddress } from '@/stores/my-account'
import { useMutation, UseMutationOptions } from '@tanstack/react-query'
import useWithoutAnonLoginOptions from './useWithoutAnonLoginOptions'

type Params = SendMessageParams & {
captchaToken: string
captchaToken: string | null
}
export default function useRequestTokenAndSendMessage(
options?: UseMutationOptions<void, unknown, Params, unknown>
) {
const address = useMyMainAddress()
const { withoutAnonLoginOptions, promptUserForLogin } =
useWithoutAnonLoginOptions()

const { mutateAsync: requestToken } = useRequestToken()
const { mutateAsync: sendMessage } = useSendMessage()
Expand All @@ -22,15 +25,23 @@ export default function useRequestTokenAndSendMessage(
const { captchaToken, ...sendMessageParams } = params
let usedAddress: string = address ?? ''
if (!address) {
const address = await login()
if (!address) throw new Error('Failed to login')
usedAddress = address
if (withoutAnonLoginOptions) {
const loginAddress = await promptUserForLogin()
if (!loginAddress) return
usedAddress = loginAddress
} else {
const address = await login()
if (!address) throw new Error('Failed to login')
usedAddress = address
}
}

await Promise.all([
requestToken({ address: usedAddress, captchaToken }),
sendMessage(sendMessageParams),
])
const promises: Promise<any>[] = [sendMessage(sendMessageParams)]
if (captchaToken) {
promises.push(requestToken({ address: usedAddress, captchaToken }))
}

await Promise.all(promises)
}

return useMutation(requestTokenAndSendMessage, options)
Expand Down
41 changes: 41 additions & 0 deletions src/hooks/useWithoutAnonLoginOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getChatIdsWithoutAnonLoginOptions } from '@/constants/chat'
import { useLoginModal } from '@/stores/login-modal'
import { useMyAccount } from '@/stores/my-account'
import { generateManuallyTriggeredPromise } from '@/utils/promise'
import { getIdFromSlug } from '@/utils/slug'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useRef } from 'react'

const openLoginModal = () => {
useLoginModal.getState().setIsOpen(true)
}

export default function useWithoutAnonLoginOptions() {
const { query } = useRouter()
const chatId =
typeof query.slug === 'string' ? getIdFromSlug(query.slug) : undefined
const withoutAnonLoginOptions = getChatIdsWithoutAnonLoginOptions().includes(
chatId ?? ''
)

const isOpen = useLoginModal((state) => state.isOpen)
const waitingLoginResolvers = useRef<VoidFunction[]>([])
useEffect(() => {
if (!isOpen) {
waitingLoginResolvers.current.forEach((resolver) => resolver())
waitingLoginResolvers.current = []
}
}, [isOpen])

const setIsOpen = useLoginModal((state) => state.setIsOpen)

const promptUserForLogin = useCallback(async () => {
setIsOpen(true)
const { getPromise, getResolver } = generateManuallyTriggeredPromise()
waitingLoginResolvers.current.push(getResolver())
await getPromise()
return useMyAccount.getState().address
}, [setIsOpen])

return { withoutAnonLoginOptions, promptUserForLogin }
}
18 changes: 14 additions & 4 deletions src/services/subsocial/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import useWithoutAnonLoginOptions from '@/hooks/useWithoutAnonLoginOptions'
import { useRequestToken } from '@/services/api/mutation'
import { getHasEnoughEnergy, useMyAccount } from '@/stores/my-account'
import {
Expand Down Expand Up @@ -49,15 +50,24 @@ export default function useCommonTxSteps<Data, ReturnValue>(
const { mutateAsync: requestToken } = useRequestToken()
const login = useMyAccount((state) => state.login)

const needToRunCaptcha = !address || !hasEnoughEnergy
const { withoutAnonLoginOptions, promptUserForLogin } =
useWithoutAnonLoginOptions()
const needToRunCaptcha =
(!address && !withoutAnonLoginOptions) || (address && !hasEnoughEnergy)

const workerFunc = async (params: { captchaToken?: string } & Data) => {
const { captchaToken } = params
let usedAddress: string = address ?? ''
if (!address) {
const address = await login()
if (!address) throw new Error('Failed to login')
usedAddress = address
if (withoutAnonLoginOptions) {
const address = await promptUserForLogin()
if (!address) return
usedAddress = address
} else {
const address = await login()
if (!address) throw new Error('Failed to login')
usedAddress = address
}
}

if (!hasEnoughEnergy && captchaToken) {
Expand Down
20 changes: 20 additions & 0 deletions src/stores/login-modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { create } from './utils'

type State = {
isOpen: boolean
}

type Actions = {
setIsOpen: (isOpen: boolean) => void
}

const initialState: State = {
isOpen: false,
}

export const useLoginModal = create<State & Actions>()((set) => ({
...initialState,
setIsOpen: (isOpen) => {
set({ isOpen })
},
}))

0 comments on commit b8f468b

Please sign in to comment.