Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught (in promise) PaymentMethodNotAttachedError: Card has not been attached to the page. It must be attached before a payment method can be tokenized #46

Closed
chinesehemp opened this issue Apr 14, 2022 · 2 comments · Fixed by #47
Assignees
Labels
bug Something isn't working

Comments

@chinesehemp
Copy link

What version of React are you using?

17.0.1

What version of Node.js are you using?

16.4.0

What browser are you using?

Chrome

What operating system are you using?

macOS

How are you deploying your application?

firebase

Describe the Bug

I'm getting this error in the console...

Using v2.5.0 of the package (latest) and never had this error previously.

Screenshot 2022-04-14 at 18 29 23

Expected Behavior

No error appears in the console.

To Reproduce

import React, { useState } from "react"
import { SafeAreaView } from 'react-native-safe-area-context';
import { ScrollView, View, Image } from "react-native"
import { Appbar, ActivityIndicator, Chip, Dialog, Portal, Paragraph, Button } from "react-native-paper"
import { LinearGradient } from "expo-linear-gradient"
import NavigationService from "../../navigation/NavigationService"
import { RouteProp, Theme } from "@react-navigation/native"
import { functions } from "../../services/firebase"
import { useFunctionsCall } from "@react-query-firebase/functions"
import { SquarePaymentsForm, CreditCardInput } from "react-square-web-payments-sdk"
import { TokenResult, VerifyBuyerResponseDetails } from "@square/web-payments-sdk-types"
import tailwind from "tailwind-rn"
import { GetEvent } from "../../services/react-query/queries/fl_event"
import { useQueryClient } from "react-query"

type RequestData = object
type ResponseData = object

interface IProps {
  theme: Theme
  route: RouteProp<{
    params: {
      about: string,
      doorTime: string,
      eventId: string,
      price: string,
      startDate: string
    }
  }, "params">
}

const Pay: React.FC<IProps> = ({ route }) => {
  const [isError, setIsError] = useState(false)
  const [paymentDialogVisible, setPaymentDialogVisible] = useState(false)
  const [errorDialogVisible, setErrorDialogVisible] = useState(false)
  const [dialogError, setDialogError] = useState("")
  const { status, isLoading, data } = GetEvent(route.params.eventId)

  const amountString = (parseInt(route.params.price) / 100).toFixed(2)
  console.log("amountString", amountString)
  const squareCreatePayment = useFunctionsCall<RequestData, ResponseData>(
    functions,
    "squareCreatePayment",
    {},
    {
      onSuccess(data) {
        console.log("squareCreatePayment SUCCESS: ", data)
        createTicket(data.payment)
      },
      onError(error) {
        console.error("squareCreatePayment response error", error)
        setPaymentDialogVisible(false)
        setDialogError(JSON.stringify(error))
        setErrorDialogVisible(true)
      },
      onMutate(variables) {
        console.log("squareCreatePayment VARIABLES: ", variables)
      }
    }
  )

  const queryClient = useQueryClient()

  const firebaseCreateTicket = useFunctionsCall<RequestData, ResponseData>(
    functions,
    "firebaseCreateTicket",
    {},
    {
      onSuccess(data) {
        console.log("firebaseCreateTicket SUCCESS: ", data)
        setPaymentDialogVisible(false)
        console.log("invalidating event query Event: ", route.params.eventId)
        queryClient.invalidateQueries(["Event", route.params.eventId])
        queryClient.invalidateQueries(["Tickets", route.params.eventId])
        NavigationService.navigate('Ticket', { id: data })
      },
      onError(error) {
        console.error("firebaseCreateTicket ERROR: ", error)
        setPaymentDialogVisible(false)
      },
      onMutate(variables) {
        console.log("firebaseCreateTicket VARIABLES: ", variables)
      }
    }
  )
  const createPayment = (token: TokenResult, buyer: VerifyBuyerResponseDetails) => {
    if (!isError) {
      setPaymentDialogVisible(true)
      squareCreatePayment.mutate({
        token,
        buyer,
        route,
      })
    } else {
      console.log("createPayment Error")
    }
  }
  const createTicket = (payment: any, buyer: VerifyBuyerResponseDetails) => {
    console.log("createTicket payment: ", payment)
    firebaseCreateTicket.mutate({
      route,
      payment,
      buyer,
    })
  }
  return (
    <SafeAreaView style={tailwind("flex-1")}>
      <Appbar
        style={{
          height: 50
        }}
      >
        <Appbar.BackAction
          onPress={() => {
            NavigationService.navigate('Event', { id: route.params.eventId })
          }}
          color="#FFF"
        />
        <Appbar.Content
          title="Purchase ticket"
          titleStyle={tailwind("text-base font-medium -ml-4")}
          subtitle={data && data.about}
          subtitleStyle={tailwind("text-xs -ml-4")}
        />
      </Appbar>
      {isLoading && <ActivityIndicator style={tailwind("mt-2")} animating={true} color={"#000"} />}
      <ScrollView>
        {data &&
          <>
            <View
              style={tailwind("w-full h-48 justify-center")}
            >
              <Image
                source={{ uri: data.image[0].url }}
                style={tailwind("w-full h-full")}
              />
              <LinearGradient
                colors={["transparent", "rgba(0,0,0,0.8)"]}
                style={tailwind("absolute top-0 left-0 right-0 h-48")}
              />
            </View>
            <View style={tailwind("mx-4 mt-2")}>
              <SquarePaymentsForm
                applicationId="hidden-from-public"
                locationId="hidden-from-public"
                cardTokenizeResponseReceived={async (token, buyer) => {
                  // console.log({ token, buyer })
                  createPayment(token, buyer)
                }}
                createVerificationDetails={() => ({
                  amount: amountString,
                  /* collected from the buyer */
                  billingContact: {
                    addressLines: ["123 Main Street", "Apartment 1"],
                    familyName: "Doe",
                    givenName: "John",
                    countryCode: "GB",
                    city: "London",
                  },
                  currencyCode: "GBP",
                  intent: "CHARGE",
                })}
              >
                <CreditCardInput
                  focus="cardNumber"
                  text={"Pay £" + amountString}
                  overrideStyles={{
                    background: "black",
                  }}
                  errorClassAdded={
                    () => {
                      setIsError(true)
                    }
                  }
                  errorClassRemoved={
                    () => {
                      setIsError(false)
                    }
                  }
                  focusClassAdded={
                    () => {
                      setPaymentDialogVisible(false)
                    }
                  }
                />
              </SquarePaymentsForm>
            </View>
          </>
        }
      </ScrollView>
      <Portal>
        <Dialog
          visible={paymentDialogVisible}
          onDismiss={() => setPaymentDialogVisible(!paymentDialogVisible)}
          style={tailwind("bg-white items-center	")}
        >
          <Dialog.Title>
            Purchase in progress
          </Dialog.Title>
          <Dialog.Content>
            <ActivityIndicator style={tailwind("mb-6")} animating={true} color={"#000"} />
            <Paragraph>Processing your payment</Paragraph>
          </Dialog.Content>
        </Dialog>
        <Dialog
          visible={errorDialogVisible}
          onDismiss={() => setErrorDialogVisible(false)}
          style={tailwind("bg-white")}
        >
          <Dialog.Title>Error</Dialog.Title>
          <Dialog.Content>
            <Paragraph>Ops... This is embarresing. Something went wrong. Here"s the error message: {dialogError}</Paragraph>
          </Dialog.Content>
          <Dialog.Actions>
            <Button
              onPress={() => setErrorDialogVisible(false)}
              color="#000"
              mode="text"
              uppercase={false}
            >
              Okay
            </Button>
          </Dialog.Actions>
        </Dialog>
      </Portal>
    </SafeAreaView>
  )
}

export default Pay
@danestves danestves mentioned this issue Apr 25, 2022
4 tasks
@danestves danestves added the bug Something isn't working label Apr 25, 2022
@danestves danestves self-assigned this Apr 25, 2022
@danestves danestves linked a pull request Apr 25, 2022 that will close this issue
4 tasks
@danestves
Copy link
Collaborator

danestves commented Apr 27, 2022

Hi @chinesehemp, we have identified the error and have fixed on react-square-web-payments-sdk@canary but this canary version have many breaking changes, if you want you can give it a try or wait until we have the PR finished and the new version/docs published ✌️

@danestves
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants