基本完成iap和金币支付

This commit is contained in:
yezian 2024-06-14 18:12:16 +08:00
parent f28703244d
commit eba607cd10
13 changed files with 655 additions and 45 deletions

4
.env
View File

@ -1,3 +1,5 @@
EXPO_PUBLIC_API_URL=https://api.tiefen.fun
EXPO_PUBLIC_RSA_KEY=-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMXPIjKV6CMi5O9tIXJWNIfnqXjqOZ1KmRByRAP073DU+gzMLygzEsrztJzbz/K/Julkz6XhheZ8vdz+boAl1HsCAwEAAQ==-----END PUBLIC KEY-----
EXPO_PUBLIC_WEB_URL=https://tiefen.fun
EXPO_PUBLIC_WEB_URL=https://tiefen.fun
EXPO_PUBLIC_RC_APPLE_KEY=appl_QkkgJKLkfdCfcwPvsncIdbwPwQk
SENTRY_AUTH_TOKEN=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

View File

@ -0,0 +1,245 @@
import { View, Text, Modal, TouchableOpacity } from "react-native";
import React, { useState, useEffect } from "react";
import { useTailwind } from "tailwind-rn";
import { Button } from "@rneui/themed";
import Toast from "react-native-toast-message";
import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
import { get } from "../../utils/storeInfo";
import { useNavigation } from "@react-navigation/native";
export default function CoinPayModal({
visible,
setVisible,
url,
body = {},
product,
coinPrice,
validity,
info,
onPurchaseDone = () => {},
}) {
const tailwind = useTailwind();
const navigation = useNavigation();
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
//
const [coinBalance, setCoinBalance] = useState();
useEffect(() => {
if (!visible) {
setIsCoinEnough(true);
setIsWaitingConfirm(false);
return;
}
const init = async () => {
const base = await baseRequest();
const account = await get("account");
const body = {
...base,
mid: account.mid,
};
const signature = await generateSignature(body);
const _response = await fetch(
`${apiUrl}/api/account/list_by_mid?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const _data = await _response.json();
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
setCoinBalance(_data.data.account.gold_num);
};
init();
}, [visible]);
//
const [isCoinEnough, setIsCoinEnough] = useState(true);
const [isWaitingConfirm, setIsWaitingConfirm] = useState(false);
const checkCoinBalance = async () => {
if (coinBalance < coinPrice) {
setIsCoinEnough(false);
return;
}
setIsWaitingConfirm(true);
};
//
const handleCoinPay = async () => {
try {
const base = await baseRequest();
const _body = {
...base,
...body,
pay_type: "coin",
from: "app",
};
const signature = await generateSignature(_body);
const _response = await fetch(`${apiUrl + url}?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(_body),
});
const _data = await _response.json();
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
setVisible(false);
onPurchaseDone();
} catch (error) {
console.error(error);
}
};
return (
<Modal
visible={visible}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<TouchableOpacity
activeOpacity={1}
onPress={() => setVisible(false)}
style={{
backgroundColor: "#00000080",
...tailwind("flex-1 justify-center items-center"),
}}
>
<TouchableOpacity
activeOpacity={1}
style={tailwind("p-4 rounded-2xl bg-[#17161A] items-center w-3/4")}
>
<View style={tailwind("flex flex-col w-full px-4")}>
{isCoinEnough ? (
isWaitingConfirm ? (
<>
<Text
style={tailwind(
"text-white text-xl font-semibold text-center mt-2"
)}
>
本次消费将扣除您{coinPrice}金币是否确认购买
</Text>
<Text style={tailwind("text-white text-sm text-center mt-2")}>
当前余额{coinBalance}金币
</Text>
</>
) : (
<>
<Text
style={tailwind("text-white text-xl font-semibold mt-2")}
>
项目{product}
</Text>
<Text
style={tailwind("text-white text-xl font-semibold mt-2")}
>
价格{coinPrice}金币
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm mt-2")}>
1 RMB = 10 金币
</Text>
{validity && (
<Text
style={tailwind("text-white text-xl font-semibold mt-2")}
>
有效期{validity}
</Text>
)}
{info && (
<Text style={tailwind("text-[#FFFFFF80] text-sm mt-2")}>
{info}
</Text>
)}
</>
)
) : (
<>
<Text
style={tailwind(
"text-white text-xl font-semibold text-center mt-2"
)}
>
余额不足请先充值金币
</Text>
<Text style={tailwind("text-white text-sm text-center mt-2")}>
当前余额{coinBalance}金币
</Text>
</>
)}
{!isWaitingConfirm && isCoinEnough && (
<Button
onPress={checkCoinBalance}
color="#FF669E"
radius="999"
size="md"
titleStyle={tailwind("text-base")}
containerStyle={tailwind("w-full mt-4")}
>
购买
</Button>
)}
{isWaitingConfirm && (
<Button
onPress={handleCoinPay}
color="#FF669E"
radius="999"
size="md"
titleStyle={tailwind("text-base")}
containerStyle={tailwind("w-full mt-4")}
>
确认
</Button>
)}
{!isCoinEnough && (
<Button
onPress={() => {
navigation.navigate("Wallet");
setVisible(false);
setIsCoinEnough(true);
}}
color="#FF669E"
radius="999"
size="md"
titleStyle={tailwind("text-base")}
containerStyle={tailwind("w-full mt-4")}
>
前往充值
</Button>
)}
<TouchableOpacity
onPress={() => setVisible(false)}
style={tailwind("mt-4")}
>
<Text
style={tailwind(
"text-[#FFFFFF80] text-base font-medium text-center"
)}
>
取消
</Text>
</TouchableOpacity>
</View>
</TouchableOpacity>
</TouchableOpacity>
</Modal>
);
}

View File

@ -22,6 +22,7 @@ import { Icon } from "@rneui/themed";
import ParsedText from "react-native-parsed-text";
import * as Linking from "expo-linking";
import { useImageViewer } from "../../context/ImageViewProvider";
import CoinPayModal from "../CoinPayModal";
//todo:
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
@ -34,6 +35,9 @@ export default function SpacePost({ data }) {
);
const [showVideo, setShowVideo] = useState(false);
//Modal
const [isCoinPayModalVisible, setIsCoinPayModalVisible] = useState(false);
//
const [isFullTextBtnShow, setIsFullTextBtnShow] = useState(false);
const [isTextCollapsed, setIsTextCollapsed] = useState(true);
@ -301,7 +305,11 @@ export default function SpacePost({ data }) {
{data.c_type === 1 && data.is_zone_moment_unlocked === 0 && (
<TouchableOpacity
activeOpacity={1}
onPress={() =>
onPress={() => {
if (Platform.OS === "ios") {
setIsCoinPayModalVisible(true);
return;
}
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
@ -309,8 +317,8 @@ export default function SpacePost({ data }) {
data?.zid +
"/h5_zone_moment/" +
data?.id,
})
}
});
}}
style={{
backgroundColor:
data.is_ironfan_visible === 1 ? "#301024" : "#331F0B",
@ -335,7 +343,9 @@ export default function SpacePost({ data }) {
...tailwind("text-base font-semibold ml-1"),
}}
>
{data.price / 100}
{Platform.OS === "ios"
? data.coin_price
: data.price / 100}
</Text>
<Text
style={{
@ -344,7 +354,7 @@ export default function SpacePost({ data }) {
...tailwind("text-sm font-medium"),
}}
>
{Platform.OS === "ios" ? "金币" : ""}
</Text>
</View>
<View style={tailwind("flex flex-row items-center")}>
@ -373,7 +383,11 @@ export default function SpacePost({ data }) {
</View>
{data.is_ironfan_visible === 1 && (
<Text style={tailwind("text-xs text-[#FFFFFF40] mt-1")}>
空间内任意消费满{data.ironfanship_price / 100}元即可成为铁粉
空间内任意消费满
{Platform.OS === "ios"
? data.ironfanship_coin_price + "金币"
: data.ironfanship_price / 100 + "元"}
即可成为铁粉
</Text>
)}
</TouchableOpacity>
@ -412,7 +426,9 @@ export default function SpacePost({ data }) {
...tailwind("text-base font-semibold ml-1"),
}}
>
{data.price / 100}
{Platform.OS === "ios"
? data.coin_price
: data.price / 100}
</Text>
<Text
style={{
@ -423,7 +439,7 @@ export default function SpacePost({ data }) {
...tailwind("text-sm font-medium"),
}}
>
{Platform.OS === "ios" ? "金币" : ""}
</Text>
</View>
<View style={tailwind("flex flex-row items-center")}>
@ -494,7 +510,9 @@ export default function SpacePost({ data }) {
...tailwind("text-base font-semibold ml-1"),
}}
>
{data.price / 100}
{Platform.OS === "ios"
? data.coin_price
: data.price / 100}
</Text>
<Text
style={{
@ -503,7 +521,7 @@ export default function SpacePost({ data }) {
...tailwind("text-sm font-medium"),
}}
>
{Platform.OS === "ios" ? "金币" : ""}
</Text>
</View>
<View style={tailwind("flex flex-row items-center")}>
@ -528,7 +546,11 @@ export default function SpacePost({ data }) {
</View>
{data.is_ironfan_visible === 1 && (
<Text style={tailwind("text-xs text-[#FFFFFF40] mt-1")}>
空间内任意消费满{data.ironfanship_price / 100}元即可成为铁粉
空间内任意消费满
{Platform.OS === "ios"
? data.ironfanship_coin_price + "金币"
: data.ironfanship_price / 100 + "元"}
即可成为铁粉
</Text>
)}
</TouchableOpacity>
@ -585,6 +607,27 @@ export default function SpacePost({ data }) {
</View>
</View>
<View style={tailwind("h-[3px] rounded-full mx-4 bg-[#FFFFFF26]")}></View>
{/* 金币支付Modal */}
<CoinPayModal
visible={isCoinPayModalVisible}
setVisible={setIsCoinPayModalVisible}
url="/api/zone/create_order"
body={{
zid: data?.zid,
moment_id: data?.id,
product_id: "h5_zone_moment",
}}
product="单条付费动态"
coinPrice={data?.coin_price}
info="购买完成后,请刷新当前页面查看"
onPurchaseDone={() =>
Toast.show({
type: "success",
text1: "购买完成,请刷新当前页面查看",
topOffset: 60,
})
}
/>
</View>
);
}

View File

@ -3,6 +3,7 @@ import { Platform } from "react-native";
import Purchases, { LOG_LEVEL } from "react-native-purchases";
import { AuthContext } from "../App";
import { get } from "../utils/storeInfo";
import Toast from "react-native-toast-message";
const IapContext = createContext();
@ -54,10 +55,25 @@ export const IapProvider = ({ children }) => {
}
};
const restorePurchases = async () => {
if (Platform.OS !== "ios") return;
try {
await Purchases.restorePurchases();
Toast.show({
type: "success",
text1: "恢复成功",
topOffset: 60,
});
} catch (e) {
console.error(e);
}
};
const value = {
packages,
purchasePackage,
getCustomerInformation,
restorePurchases,
};
if (!isReady) return <></>;

View File

@ -23,7 +23,7 @@ export default function Login() {
const [index, setIndex] = useState(0);
const [routes] = useState([
{ key: "phoneNumLogin", title: "验证码登录" },
{ key: "passwordLogin", title: "账号密码登" },
{ key: "passwordLogin", title: "账号密码登" },
]);
const renderScene = useCallback(

View File

@ -4,6 +4,7 @@ import {
TouchableOpacity,
ScrollView,
Image as NativeImage,
Platform,
} from "react-native";
import React, { useState, useEffect, useCallback } from "react";
import { useTailwind } from "tailwind-rn";
@ -24,7 +25,7 @@ export default function My({ navigation }) {
//
const [data, setData] = useState();
const [vipPrice, setVipPrice] = useState();
const [vipPrice, setVipPrice] = useState({});
useEffect(() => {
const initData = async () => {
const account = await get("account");
@ -59,7 +60,7 @@ export default function My({ navigation }) {
});
return;
}
setVipPrice(_data.data.product.real_price / 100);
setVipPrice(_data.data.product);
} catch (error) {
console.error(error);
}
@ -352,7 +353,9 @@ export default function My({ navigation }) {
activeOpacity={1}
onPress={() =>
navigation.navigate("WebWithoutHeader", {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
uri:
process.env.EXPO_PUBLIC_WEB_URL +
`/vip?use_coinpay=${Platform.OS === "ios" ? "1" : "0"}`,
})
}
style={tailwind(
@ -388,7 +391,12 @@ export default function My({ navigation }) {
)}
>
<Text style={tailwind("text-white text-sm font-medium")}>
¥{vipPrice}/永久
{`${
Platform.OS === "ios"
? vipPrice?.real_coin_price + "金币"
: "¥" + vipPrice?.real_price / 100
}`}
/
</Text>
</View>
)}

View File

@ -0,0 +1,25 @@
import { View, Text } from "react-native";
import React from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
export default function RechargeGold({ navigation, route }) {
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
return (
<View
style={{
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
<Text>Example</Text>
</View>
);
}

View File

@ -1,4 +1,10 @@
import { View, Text, ScrollView, TouchableOpacity } from "react-native";
import {
View,
Text,
ScrollView,
TouchableOpacity,
Platform,
} from "react-native";
import React, { useState, useEffect, useContext } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
@ -6,11 +12,15 @@ import { Icon, Button } from "@rneui/themed";
import * as FileSystem from "expo-file-system";
import { AuthContext } from "../../../App";
import MyDivider from "../../../components/MyDivider";
import { useIap } from "../../../context/IapProvider";
export default function SelectSettingItem({ navigation }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
//
const { restorePurchases } = useIap();
//退
const { signOut } = useContext(AuthContext);
@ -67,6 +77,16 @@ export default function SelectSettingItem({ navigation }) {
<SettingItem title="黑名单" to="BannedList" />
<SettingItem title="意见反馈" to="Feedback" />
<SettingItem title="账号注销" to="DeleteAccount" />
{Platform.OS === "ios" && (
<TouchableOpacity
onPress={restorePurchases}
style={tailwind("flex-row justify-between pt-4 pb-2")}
>
<Text style={tailwind("text-base text-white")}>恢复购买</Text>
<Icon name="chevron-forward-outline" type="ionicon" color="white" />
</TouchableOpacity>
)}
<MyDivider />
<TouchableOpacity
onPress={clearCache}
style={tailwind("flex-row justify-between pt-4 pb-2")}

View File

@ -4,6 +4,7 @@ import {
Image as NativeImage,
TouchableOpacity,
ScrollView,
Platform,
} from "react-native";
import React, { useState, useCallback } from "react";
import { useTailwind } from "tailwind-rn";
@ -20,6 +21,7 @@ import SpaceIntroduceSkeleton from "./skeleton";
import { usePreventScreenCapture } from "expo-screen-capture";
import { useFocusEffect } from "@react-navigation/native";
import { useImageViewer } from "../../context/ImageViewProvider";
import CoinPayModal from "../../components/CoinPayModal";
export default function SpaceIntroduce({ navigation, route }) {
usePreventScreenCapture();
@ -130,6 +132,9 @@ export default function SpaceIntroduce({ navigation, route }) {
//Modal
const [showVideo, setShowVideo] = useState(false);
//Modal
const [isCoinPayModalVisible, setIsCoinPayModalVisible] = useState(false);
//
if (isLoading) return <SpaceIntroduceSkeleton />;
@ -345,14 +350,19 @@ export default function SpaceIntroduce({ navigation, route }) {
onPress={
data?.admission_price === 0
? handleJoinFreeSpace
: () =>
: () => {
if (Platform.OS === "ios") {
setIsCoinPayModalVisible(true);
return;
}
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.id +
"/h5_zone_admission/0",
})
});
}
}
style={tailwind(
"flex flex-row items-center justify-center h-12 rounded-full px-10 bg-[#FF669E]"
@ -367,12 +377,28 @@ export default function SpaceIntroduce({ navigation, route }) {
<Text style={tailwind("text-base text-white font-medium ml-2")}>
{data?.admission_price === 0
? "免费加入"
: `${data?.admission_price / 100}元立即加入`}
: `${
Platform.OS === "ios"
? data?.admission_coin_price + "金币"
: data?.admission_price / 100 + "元"
}立即加入`}
</Text>
<NativeImage source={require("../../assets/icon/32DP/link.png")} />
</TouchableOpacity>
</View>
)}
{/* 金币支付Modal */}
<CoinPayModal
visible={isCoinPayModalVisible}
setVisible={setIsCoinPayModalVisible}
url="/api/zone/create_order"
body={{ zid: data?.id, product_id: "h5_zone_admission" }}
product="当前空间成员"
coinPrice={data?.admission_coin_price}
onPurchaseDone={() =>
navigation.replace("SpaceIntroduce", route.params)
}
/>
{/* 查看微信Modal */}
{data?.streamer_ext?.wechat_lock_type === 0 ? (
<GetWechatModal

View File

@ -7,6 +7,7 @@ import {
Animated,
Easing,
Modal,
Platform,
} from "react-native";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { useTailwind } from "tailwind-rn";
@ -30,6 +31,7 @@ import { LinearGradient } from "expo-linear-gradient";
import { usePreventScreenCapture } from "expo-screen-capture";
import { Svg, Path } from "react-native-svg";
import MyModal from "../../components/MyModal";
import CoinPayModal from "../../components/CoinPayModal";
export default function StreamerSpace({ navigation, route }) {
usePreventScreenCapture();
@ -45,6 +47,9 @@ export default function StreamerSpace({ navigation, route }) {
//退Modal
const [isRefundingModalVisible, setIsRefundingModalVisible] = useState(false);
//Modal
const [isCoinPayModalVisible, setIsCoinPayModalVisible] = useState(false);
//
const [data, setData] = useState({});
const getData = async () => {
@ -257,14 +262,37 @@ export default function StreamerSpace({ navigation, route }) {
color="#FF669E"
variant="determinate"
/>
<Text style={tailwind("text-sm text-[#FF669E] font-medium")}>{`${
data?.expenditure / 100
} / ${data?.ironfanship_price / 100}`}</Text>
<Text style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-2")}>
空间内累计消费达到¥{data?.ironfanship_price / 100}即可成为
<Text style={tailwind("text-[#FF669E]")}>铁粉</Text>
可查看所有铁粉专享内容哦快来成为我的铁粉吧
</Text>
{Platform.OS === "ios" ? (
<>
<Text
style={tailwind("text-sm text-[#FF669E] font-medium")}
>{`${data?.expenditure / 10} / ${
data?.ironfanship_coin_price
}`}</Text>
<Text
style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-2")}
>
空间内累计消费达到{data?.ironfanship_coin_price}金币即可成为
<Text style={tailwind("text-[#FF669E]")}>铁粉</Text>
可查看所有铁粉专享内容哦快来成为我的铁粉吧
</Text>
</>
) : (
<>
<Text
style={tailwind("text-sm text-[#FF669E] font-medium")}
>{`${data?.expenditure / 100} / ${
data?.ironfanship_price / 100
}`}</Text>
<Text
style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-2")}
>
空间内累计消费达到¥{data?.ironfanship_price / 100}即可成为
<Text style={tailwind("text-[#FF669E]")}>铁粉</Text>
可查看所有铁粉专享内容哦快来成为我的铁粉吧
</Text>
</>
)}
<Button
onPress={() => {
setIndex(1);
@ -444,10 +472,15 @@ export default function StreamerSpace({ navigation, route }) {
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
{`${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
{Platform.OS === "ios"
? `${parseInt(data?.expenditure / 10, 10)}/${parseInt(
data?.ironfanship_coin_price,
10
)}`
: `${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
</Text>
</View>
</TouchableOpacity>
@ -456,14 +489,19 @@ export default function StreamerSpace({ navigation, route }) {
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
: () => {
if (Platform.OS === "ios") {
setIsCoinPayModalVisible(true);
return;
}
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.id +
"/h5_zone_superfanship/0",
})
});
}
}
style={tailwind("flex flex-col items-center")}
>
@ -477,6 +515,16 @@ export default function StreamerSpace({ navigation, route }) {
? "尊贵超粉"
: "成为超粉"}
</Text>
{data?.is_superfanship_give_wechat === 1 && (
<Text
style={{
fontSize: 10,
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
赠微信
</Text>
)}
</TouchableOpacity>
)}
<TouchableOpacity
@ -568,14 +616,19 @@ export default function StreamerSpace({ navigation, route }) {
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
: () => {
if (Platform.OS === "ios") {
setIsCoinPayModalVisible(true);
return;
}
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.id +
"/h5_zone_superfanship/0",
})
});
}
}
style={tailwind("flex flex-col items-center")}
>
@ -589,6 +642,16 @@ export default function StreamerSpace({ navigation, route }) {
? "尊贵超粉"
: "成为超粉"}
</Text>
{data?.is_superfanship_give_wechat === 1 && (
<Text
style={{
fontSize: 10,
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
赠微信
</Text>
)}
</TouchableOpacity>
)}
<TouchableOpacity
@ -612,15 +675,36 @@ export default function StreamerSpace({ navigation, route }) {
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
{`${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
{Platform.OS === "ios"
? `${parseInt(data?.expenditure / 10, 10)}/${parseInt(
data?.ironfanship_coin_price,
10
)}`
: `${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
</Text>
</View>
</TouchableOpacity>
</View>
)}
{/* 金币支付Modal */}
<CoinPayModal
visible={isCoinPayModalVisible}
setVisible={setIsCoinPayModalVisible}
url="/api/zone/create_order"
body={{ zid: data?.id, product_id: "h5_zone_superfanship" }}
product="当前空间超粉"
coinPrice={data?.superfanship_coin_price}
validity={data?.superfanship_validity}
info={`开通后可免费查看本空间内全部动态${
data?.is_superfanship_give_wechat === 1 && "并且解锁Ta的微信。"
}`}
onPurchaseDone={() =>
navigation.replace("StreamerSpace", route.params)
}
/>
{/* 点击成为铁粉Modal */}
<BecomeIronFanModal />
{/* 创建帖子Modal */}

View File

@ -1,4 +1,4 @@
import { View, Text, Image, TouchableOpacity } from "react-native";
import { View, Text, Image, TouchableOpacity, Platform } from "react-native";
import React, { useState, useCallback } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
@ -11,12 +11,16 @@ import Toast from "react-native-toast-message";
import * as Linking from "expo-linking";
import { generateSignature } from "../../utils/crypto";
import { useFocusEffect } from "@react-navigation/native";
import { useIap } from "../../context/IapProvider";
export default function Wallet({ navigation, route }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const headerHeight = useHeaderHeight();
//iap
const { packages } = useIap();
const [tokenAndMobilePhone, setTokenAndMobilePhone] = useState("");
const [data, setData] = useState("");
//focus
@ -121,7 +125,14 @@ export default function Wallet({ navigation, route }) {
onPress={() =>
navigation.navigate("WebWithHeader", {
title: "充值中心",
uri: process.env.EXPO_PUBLIC_WEB_URL + "/pay",
uri:
process.env.EXPO_PUBLIC_WEB_URL +
`/pay${
Platform.OS === "ios"
? "?product=" +
encodeURIComponent(JSON.stringify(packages))
: ""
}`,
})
}
style={tailwind("flex-row justify-between items-center py-4")}

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { Alert } from "react-native";
import { Alert, Modal, View, Text } from "react-native";
import { WebView } from "react-native-webview";
import * as FileSystem from "expo-file-system";
import * as MediaLibrary from "expo-media-library";
@ -9,8 +9,12 @@ import Toast from "react-native-toast-message";
import MyModal from "../../components/MyModal";
import baseRequest from "../../utils/baseRequest";
import { useIap } from "../../context/IapProvider";
import CoinPayModal from "../../components/CoinPayModal";
import { useTailwind } from "tailwind-rn";
import { Icon } from "@rneui/themed";
export default function WebWithHeader({ navigation, route }) {
const tailwind = useTailwind();
//
useEffect(() => {
navigation.setOptions({
@ -90,9 +94,30 @@ export default function WebWithHeader({ navigation, route }) {
//iap
const { packages, purchasePackage } = useIap();
const [connectingAppStore, setConnectingAppStore] = useState(false);
const purchase = async (product) => {
setConnectingAppStore(true);
const pack = packages.find((p) => p.identifier === product);
await purchasePackage(pack);
setConnectingAppStore(false);
};
//
const [isCoinPayModalVisible, setIsCoinPayModalVisible] = useState(false);
const [coinPayData, setCoinPayData] = useState({
url: "",
body: {},
product: "",
coinPrice: null,
validity: "",
info: "",
onPurchaseDone: () => {},
});
const purchaseByCoin = async (data) => {
setCoinPayData((prev) => {
return { ...prev, ...data };
});
setIsCoinPayModalVisible(true);
};
//
@ -178,6 +203,9 @@ export default function WebWithHeader({ navigation, route }) {
case "IAP":
purchase(msg.data);
break;
case "COINPAY":
purchaseByCoin(msg.data);
break;
default:
break;
}
@ -205,6 +233,43 @@ export default function WebWithHeader({ navigation, route }) {
setOverlayVisible(false);
}}
/>
{/* 金币支付Modal */}
<CoinPayModal
visible={isCoinPayModalVisible}
setVisible={setIsCoinPayModalVisible}
url={coinPayData.url}
body={coinPayData.body}
product={coinPayData.product}
coinPrice={coinPayData.coinPrice}
validity={coinPayData.validity}
info={coinPayData.info}
onPurchaseDone={coinPayData.onPurchaseDone}
/>
{/* 正在连接appstore的Modal */}
<Modal
visible={connectingAppStore}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<View
style={{
backgroundColor: "#00000080",
...tailwind("flex-1 justify-center items-center"),
}}
>
<View
style={tailwind(
"flex flex-col p-4 rounded bg-[#17161A] items-center"
)}
>
<Icon type="ionicon" name="logo-apple" size={32} color="white" />
<Text style={tailwind("text-white text-base font-medium mt-4")}>
正在连接AppStore...
</Text>
</View>
</View>
</Modal>
</>
);
}

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { Alert } from "react-native";
import { Alert, Modal, View, Text } from "react-native";
import { WebView } from "react-native-webview";
import * as FileSystem from "expo-file-system";
import * as MediaLibrary from "expo-media-library";
@ -9,8 +9,12 @@ import Toast from "react-native-toast-message";
import MyModal from "../../components/MyModal";
import baseRequest from "../../utils/baseRequest";
import { useIap } from "../../context/IapProvider";
import CoinPayModal from "../../components/CoinPayModal";
import { useTailwind } from "tailwind-rn";
import { Icon } from "@rneui/themed";
export default function WebWithoutHeader({ navigation, route }) {
const tailwind = useTailwind();
//
const [overlayVisible, setOverlayVisible] = useState(false);
@ -83,9 +87,30 @@ export default function WebWithoutHeader({ navigation, route }) {
//iap
const { packages, purchasePackage } = useIap();
const [connectingAppStore, setConnectingAppStore] = useState(false);
const purchase = async (product) => {
setConnectingAppStore(true);
const pack = packages.find((p) => p.identifier === product);
await purchasePackage(pack);
setConnectingAppStore(false);
};
//
const [isCoinPayModalVisible, setIsCoinPayModalVisible] = useState(false);
const [coinPayData, setCoinPayData] = useState({
url: "",
body: {},
product: "",
coinPrice: null,
validity: "",
info: "",
onPurchaseDone: () => {},
});
const purchaseByCoin = async (data) => {
setCoinPayData((prev) => {
return { ...prev, ...data };
});
setIsCoinPayModalVisible(true);
};
//
@ -171,6 +196,9 @@ export default function WebWithoutHeader({ navigation, route }) {
case "IAP":
purchase(msg.data);
break;
case "COINPAY":
purchaseByCoin(msg.data);
break;
default:
break;
}
@ -198,6 +226,43 @@ export default function WebWithoutHeader({ navigation, route }) {
setOverlayVisible(false);
}}
/>
{/* 金币支付Modal */}
<CoinPayModal
visible={isCoinPayModalVisible}
setVisible={setIsCoinPayModalVisible}
url={coinPayData.url}
body={coinPayData.body}
product={coinPayData.product}
coinPrice={coinPayData.coinPrice}
validity={coinPayData.validity}
info={coinPayData.info}
onPurchaseDone={coinPayData.onPurchaseDone}
/>
{/* 正在连接appstore的Modal */}
<Modal
visible={connectingAppStore}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<View
style={{
backgroundColor: "#00000080",
...tailwind("flex-1 justify-center items-center"),
}}
>
<View
style={tailwind(
"flex flex-col p-4 rounded bg-[#17161A] items-center"
)}
>
<Icon type="ionicon" name="logo-apple" size={32} color="white" />
<Text style={tailwind("text-white text-base font-medium mt-4")}>
正在连接AppStore...
</Text>
</View>
</View>
</Modal>
</>
);
}