ios – Including In App Purchases to react native app utilizing expo

Spread the love


I’ve a react native app that’s utilizing expo. I’m attempting to implement IAP purchases for IOS. as customers signal as much as the app. Is it potential to have IAP added to my app while my app is configured this fashion with expo? I’ve the app setup in my apple developer account as properly so I do know this is not the problem.

I can not get the IAP purchases working throughout the app and particularly with the kinds from Typescript

I’ve been getting this error which makes me assume this isn’t potential.

ERROR  Error: E_IAP_NOT_AVAILABLE

This error is positioned at:
    in WrapperComponent (created by withDevTools(WrapperComponent))
    in withDevTools(WrapperComponent)
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in essential(RootComponent), js engine: hermes

That is the present setup that I’ve for for attempting to implement IAP.

.That is the signup web page:

import React, { useEffect, useState } from "react";
import {
  View,
  TextInput,
  Picture,
  Textual content,
  StyleSheet,
  KeyboardAvoidingView,
  ActivityIndicator,
  Platform,
  TouchableOpacity,
} from "react-native";
import { FIREBASE_AUTH } from "../../api/firebase";
import { createUserWithEmailAndPassword } from "firebase/auth";
import PrimaryButton from "../../elements/PrimaryButton/PrimaryButton";
import CustomProgressBar from "../../elements/ProgressBar/ProgressBar";
import SecondaryButton from "../../elements/SecondaryButton/SecondaryButton";
import { RouterProps } from "../../App";
import { useValidEmail, useValidPassword } from "../../hooks/useAuthHooks";
import { createUser } from "../../api/person";
import { UserProfile } from "../../fashions/UserProfile";
import { CheckBox } from "react-native-elements";
import {
  PurchaseError,
  RequestSubscription,
  requestSubscription,
  useIAP,
  validateReceiptIos,
} from "react-native-iap";

export kind NewUser = {
  uid?: string;
  firstName?: string;
  lastName?: string;
  e mail: string;
};

const PLATFORM = Platform.OS;

const subscriptionSkus = Platform.choose({
  ios: ["****"],
});

const SignupScreen = ({ navigation }: RouterProps) => {
  const [loading, setLoading] = useState(false);
  const [screen, setScreen] = useState<"signupOne" | "signupTwo">("signupOne");
  const { e mail, setEmail, emailIsValid } = useValidEmail("");
  const { password, setPassword, passwordIsValid } = useValidPassword("");
  const [isChecked, setChecked] = useState<boolean>(false);

  const {
    password: passwordConfirm,
    setPassword: setPasswordConfirm,
    passwordIsValid: passwordConfirmIsValid,
  } = useValidPassword("");
  const [newUser, setNewUser] = useState<NewUser>({ e mail: e mail });

  const createUserInAuth = async (newUser: NewUser, password: string) => {
    attempt {
      const response = await createUserWithEmailAndPassword(
        FIREBASE_AUTH,
        newUser.e mail,
        password
      );
      return response;
    } catch (error) {
      console.log(error);
    }
  };

  const handleValidation = async () => {
    setLoading(true);
    if (!newUser.e mail) {
      setLoading(false);
      return alert("Please enter an Electronic mail");
    }

    if (!emailIsValid) {
      setLoading(false);
      return alert("Please enter a legitimate Electronic mail");
    }

    if (!password) {
      setLoading(false);
      return alert("Please enter a Password");
    }

    if (!passwordIsValid) {
      setLoading(false);
      return alert("Please enter a legitimate Password");
    }

    if (!passwordConfirm) {
      setLoading(false);
      return alert("Please verify your Password");
    }

    if (!passwordConfirmIsValid) {
      setLoading(false);
      return alert("Please verify your legitimate Password");
    }

    if (password !== passwordConfirm) {
      setLoading(false);
      return alert("Passwords do not match");
    }

    if (!newUser.firstName) {
      setLoading(false);
      return alert("Please enter an First Identify");
    }

    if (!newUser.lastName) {
      setLoading(false);
      return alert("Please enter an Final Identify");
    }

    setScreen("signupTwo");
    setLoading(false);
    return true;
  };

  const {
    linked,
    subscriptions,
    getSubscriptions,
    currentPurchase,
    finishTransaction,
    purchaseHistory,
    getPurchaseHistory,
  } = useIAP();

  const handleBuySubscription = async (subscriptionId: any) => {
    attempt {
      setLoading(true);
      const buy = await requestSubscription(subscriptionId as RequestSubscription);
      console.log("Buy profitable:", buy);
      navigation!.navigate("Signin");
      setLoading(false);
    } catch (error: any) {
      console.warn("Error buying:", error.message);
      setLoading(false);
      // Deal with buy failure
    }
  };

  const handleSignUp = async () => {
    setLoading(true);

    if (!isChecked && display === "signupTwo") {
      setLoading(false);
      return alert("Please settle for the Phrases and Situations and Privateness Coverage");
    }

    attempt {
      const response = await createUserInAuth(newUser, password);

      if (newUser.firstName && newUser.lastName && response && subscriptionSkus) {
        const createdUser: UserProfile = {
          uid: response?.person.uid,
          firstName: newUser!.firstName,
          lastName: newUser!.lastName,
          e mail: e mail,
        };

        if(PLATFORM === "ios") {
          await handleBuySubscription(subscriptionSkus[0])
        } else if(PLATFORM === "android"){
          return
        }

        await createUser(createdUser)
          .then(() => {
            setLoading(false);
            navigation!.navigate("SignIn");
            console.log("Person added to database");
          })
          .catch((error) => {
            console.log("Error signing up:", error);
            alert("Join failed: " + error.message);
            setLoading(false);
          });
      }
    } catch (error) {
      console.error("Error including person: ", error);
    }
  }

  const screens = {
    signupOne: (
      <>
        <TextInput
          model={types.enter}
          placeholder="First identify"
          onChangeText={(worth) =>
            setNewUser((previous) => ({ ...previous, firstName: worth }))
          }
          worth={newUser?.firstName}
          autoCapitalize="phrases"
        />
        <TextInput
          model={types.enter}
          placeholder="Final identify"
          onChangeText={(worth) =>
            setNewUser((previous) => ({ ...previous, lastName: worth }))
          }
          worth={newUser?.lastName}
          autoCapitalize="phrases"
        />
        <TextInput
          model={types.enter}
          placeholder="Electronic mail"
          onChangeText={(worth) => {
            setEmail(worth);
            setNewUser((previous) => ({ ...previous, e mail: worth }));
          }}
          worth={e mail}
          autoCapitalize="none"
        />
        <TextInput
          model={types.enter}
          placeholder="Password"
          onChangeText={setPassword}
          worth={password}
          secureTextEntry
          autoCapitalize="none"
        />
        <TextInput
          model={types.enter}
          placeholder="Verify Password"
          onChangeText={setPasswordConfirm}
          worth={passwordConfirm}
          secureTextEntry
          autoCapitalize="none"
        />
      </>
    ),
    signupTwo: (
      <>
        <Textual content model={types.value}>Annual value of $60</Textual content>
        <View model={[styles.flexed, { width: 300 }]}>
          <CheckBox
            checked={isChecked}
            onPress={() => (isChecked ? setChecked(false) : setChecked(true))}
            containerStyle={types.checkbox}
          />
          <Textual content
            model={types.hereText}
            onPress={() => navigation!.navigate("TermsAndConditions")}
          >
            I settle for the Phrases and Situations and Privateness Coverage
          </Textual content>
        </View>
      </>
    ),
  };

  return (
    <View model={types.container}>
      <KeyboardAvoidingView habits="padding" model={types.contentContainer}>
        <CustomProgressBar
          progress={loading ? 1 : display === "signupOne" ? 0.33 : 0.66}
        />
        <Picture
          supply={require("../../property/connection.png")}
          model={types.emblem}
        />
        {screens[screen]}
        {loading ? (
          <ActivityIndicator measurement="massive" colour="#0000ff" />
        ) : (
          <PrimaryButton
            title={display === "signupOne" ? "Subsequent" : "Create"}
            onPress={() => {
              display === "signupOne" ? handleValidation() : handleSignUp();
            }}
          />
        )}
        <SecondaryButton
          title="Again"
          onPress={() => {
            display === "signupOne"
              ? navigation!.navigate("SignIn")
              : setScreen("signupOne");
          }}
        />
      </KeyboardAvoidingView>
    </View>
  );
};

const types = StyleSheet.create({
  value: {
    borderColor: "#7FB3D5",
    borderRadius: 10,
    paddingVertical: 15,
    paddingHorizontal: 40,
    marginTop: 10,
    colour: "black",
    borderWidth: 1,
    backgroundColor: "clear",
  },
  checkbox: {
    alignSelf: "heart",
  },
  emblem: {
    width: 100,
    top: 100,
    marginBottom: 20,
    marginTop: 20,
  },
  field: {
    margin: 10,
    marginBottom: 5,
    padding: 10,
    backgroundColor: "white",
    borderRadius: 7,
    shadowColor: "rgba(0, 0, 0, 0.45)",
    shadowOffset: { top: 16, width: 0 },
    shadowOpacity: 0.1,
    shadowRadius: 12,
  },
  button: {
    alignItems: "heart",
    backgroundColor: "mediumseagreen",
    borderRadius: 8,
    padding: 10,
  },
  buttonText: {
    fontSize: 16,
    fontWeight: "daring",
    colour: "white",
    textTransform: "uppercase",
  },
  specialTag: {
    colour: "white",
    backgroundColor: "crimson",
    width: 125,
    padding: 4,
    fontWeight: "daring",
    fontSize: 12,
    borderRadius: 7,
    marginBottom: 2,
  },
  flexed: {
    flexDirection: "row",
    alignItems: "heart",
  },
  hereText: {
    marginLeft: 5,
    textDecorationLine: "underline",
    colour: "blue",
  },
  signupContainer: {
    marginTop: 80,
    alignItems: "heart",
  },
  container: {
    flex: 1,
    justifyContent: "heart",
    alignItems: "heart",
    backgroundColor: "#D9D9D9",
  },
  contentContainer: {
    flex: 1,
    justifyContent: "heart",
    alignItems: "heart",
    width: 300,
  },
  title: {
    fontSize: 24,
    marginBottom: 20,
  },
  enter: {
    width: 300,
    top: 40,
    backgroundColor: "white",
    borderColor: "black",
    borderWidth: 1,
    padding: 5,
    marginBottom: 10,
  },
  errorText: {
    colour: "pink",
    fontSize: 14,
    marginBottom: 10,
  },
});

export default SignupScreen;

That is the App.tsx:

import React, { useState, useEffect } from "react";
import {
  NavigationContainer,
  NavigationProp,
  RouteProp,
} from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { FIREBASE_AUTH } from "./api/firebase";
import { onAuthStateChanged, Person } from "firebase/auth";
import SettingsPage from "./pages/SettingsPage";
import { AppRegistry } from "react-native";
import Calculator from "./pages/Calculator";
import ChangePassword from "./pages/ChangePassword";
import { QueryClient, QueryClientProvider } from "react-query";
import UpdateUser from "./pages/UpdateUser";
import HelpPage from "./pages/HelpPage";
import ForgotPassword from "./pages/ForgotPassword"
import PresetValues from "./pages/PresetValues";
// import { InAppUtils } from 'react-native-iap';
import TermsAndConditions from "./pages/auth/TermsAndConditions";
import HomeScreen from "./pages/HomeScreen";
import WorkerPage from "./pages/WorkerPage";
import BayCalculator from "./pages/BayCalculator";
import TeamPage from "./pages/TeamPage";
import LoginScreen from "./pages/auth/Login";
import SignupScreen from "./pages/auth/Signup";
import LoadingScreen from "./pages/Loading";
import { withIAPContext } from "react-native-iap";

AppRegistry.registerComponent("bay-calculator", () => App);

// InAppUtils.ios.consumePurchase('your-subscription-product-id');

const queryClient = new QueryClient();

export interface RouterProps {
  navigation?: NavigationProp<any, any>;
  route?: RouteProp<any, any>;
}

const Stack = createStackNavigator();
const InsideStack = createStackNavigator();
const AuthStack = createStackNavigator();

operate App() {
  const [isLoading, setIsLoading] = useState(true);
  const [user, setUser] = useState<Person | null>(null);
  
  operate InsideLayout({ navigation }: { navigation: any }) {
    return (
      <InsideStack.Navigator>
        <InsideStack.Display
          identify="House"
          element={HomeScreen}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="WorkerPage"
          element={WorkerPage}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="SettingsPage"
          element={SettingsPage}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="BayCalculator"
          element={BayCalculator}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="Calculator"
          element={Calculator}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="TeamPage"
          element={TeamPage}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="ChangePassword"
          element={ChangePassword}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="UpdateUser"
          element={UpdateUser}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="HelpPage"
          element={HelpPage}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="PresetValues"
          element={PresetValues}
          choices={{ headerShown: false }}
        />
      </InsideStack.Navigator>
    );
  }

  operate AuthLayout() {
    return (
      <AuthStack.Navigator>
        <Stack.Display
          identify="SignIn"
          element={LoginScreen}
          choices={{ headerShown: false }}
        />
        <Stack.Display
          identify="SignUp"
          element={SignupScreen}
          choices={{ headerShown: false }}
        />
        <Stack.Display
          identify="ForgotPassword"
          element={ForgotPassword}
          choices={{ headerShown: false }}
        />
        <InsideStack.Display
          identify="TermsAndConditions"
          element={TermsAndConditions}
          choices={{ headerShown: false }}
        />
      </AuthStack.Navigator>
    );
  }

  useEffect(() => {
    attempt {
      onAuthStateChanged(FIREBASE_AUTH, (person) => {
        setUser(person);
        setIsLoading(false);
      });
    } catch (err) {
      console.log(err);
    }
  }, []);

  return (
    <QueryClientProvider consumer={queryClient}>
      <NavigationContainer>
        <Stack.Navigator initialRouteName="SignIn">
          {isLoading ? (
            <Stack.Display
              identify="Loading"
              element={LoadingScreen}
              choices={{ headerShown: false }}
            />
          ) : person ? (
            <Stack.Display
              identify="Inside"
              element={InsideLayout}
              choices={{ headerShown: false }}
            />
          ) : (
            <Stack.Display
              identify="Auth"
              element={AuthLayout}
              choices={{ headerShown: false }}
            />
          )}
        </Stack.Navigator>
      </NavigationContainer>
    </QueryClientProvider>
  );
}

export default withIAPContext(App)

Leave a Reply

Your email address will not be published. Required fields are marked *