apple #19

Merged
txcjh merged 2 commits from apple into dev/1.0.0 2025-07-31 14:29:01 +08:00
2 changed files with 44 additions and 44 deletions

View File

@ -8,12 +8,25 @@ import ProRights from '@/components/owner/rights/proRights';
import { createOrder, createPayment, getPAy, isOrderExpired, payFailure, payProcessing, paySuccess } from '@/components/owner/rights/utils';
import { ThemedText } from '@/components/ThemedText';
import { CreateOrder } from '@/types/personal-info';
import { ErrorCode, getAvailablePurchases, getPurchaseHistories, ProductPurchase, useIAP } from 'expo-iap';
import { useLocalSearchParams, useRouter } from "expo-router";
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ActivityIndicator, Image, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ActivityIndicator, Image, Platform, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
// 根据平台动态导入 expo-iap
let useIAP: any, requestPurchase: any, getPurchaseHistories: any;
if (Platform.OS !== 'web') {
const iap = require('expo-iap');
useIAP = iap.useIAP;
requestPurchase = iap.requestPurchase;
getPurchaseHistories = iap.getPurchaseHistories;
} else {
// 为 Web 端提供 mock 实现
useIAP = () => ({ connected: false });
requestPurchase = async () => { console.log('IAP is not available on web.'); };
getPurchaseHistories = async () => [];
}
export default function Rights() {
const insets = useSafeAreaInsets();
@ -21,26 +34,19 @@ export default function Rights() {
const { t } = useTranslation();
const {
connected,
products,
subscriptions,
currentPurchase,
currentPurchaseError,
requestProducts,
requestPurchase,
finishTransaction,
validateReceipt,
ErrorCode
} = useIAP();
const { pro } = useLocalSearchParams<{
credit: string;
pro: string;
}>();
// 用户勾选协议
const [agree, setAgree] = useState<boolean>(false);
// 用户选择购买的loading
const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
// 选择购买方式
const [payChoice, setPayChoice] = useState<'ApplePay'>('ApplePay');
// 获取路由参数
const { credit, pro } = useLocalSearchParams<{
credit: string;
pro: string;
}>();
// 普通用户,会员
const [userType, setUserType] = useState<'normal' | 'premium'>('normal');
@ -66,19 +72,19 @@ export default function Rights() {
};
// 恢复购买
const restorePurchases = async () => {
try {
const purchases = await getAvailablePurchases();
console.log('Available purchases:', purchases);
// Process and validate restored purchases
for (const purchase of purchases) {
await validateAndGrantPurchase(purchase);
}
alert(t('personal:rights.restoreSuccess'));
} catch (error) {
console.error('Restore failed:', error);
}
};
// const restorePurchases = async () => {
// try {
// const purchases = await getAvailablePurchases();
// console.log('Available purchases:', purchases);
// // Process and validate restored purchases
// for (const purchase of purchases) {
// await validateAndGrantPurchase(purchase);
// }
// alert(t('personal:rights.restoreSuccess'));
// } catch (error) {
// console.error('Restore failed:', error);
// }
// };
// 处理购买
const handlePurchase = async (sku: string, transaction_id: string) => {
@ -88,15 +94,13 @@ export default function Rights() {
const res = await requestPurchase({
request: {
ios: {
sku: payType,
sku: sku,
andDangerouslyFinishTransactionAutomaticallyIOS: false,
},
},
});
console.log('Purchase success:', res);
// 支付成功
await paySuccess(transaction_id, res?.transactionId || "")
await paySuccess(transaction_id, res?.transaction_id || "")
} catch (error: any) {
console.log('Purchase failed:', error);
// 支付失败
@ -222,7 +226,7 @@ export default function Rights() {
</ThemedText>
<View style={styles.cardPoints}>
<StarSvg />
<ThemedText style={styles.cardPointsText}>{credit}</ThemedText>
<ThemedText style={styles.cardPointsText}>{pro}</ThemedText>
</View>
</View>
</View>
@ -248,7 +252,7 @@ export default function Rights() {
{/* 普通权益 */}
<Normal setUserType={setUserType} style={{ display: userType === 'normal' ? "flex" : "none" }} />
{/* 会员权益 */}
<Premium restorePurchases={restorePurchases} setPayType={setPayType} setShowTerms={setShowTerms} payType={payType} premiumPay={premiumPay} loading={loading} style={{ display: userType === 'normal' ? "none" : "flex" }} />
<Premium setPayType={setPayType} setShowTerms={setShowTerms} payType={payType} premiumPay={premiumPay} loading={loading} style={{ display: userType === 'normal' ? "none" : "flex" }} />
</View>
{/* 支付方式 */}
{/* <PayTypeModal setConfirmPay={setConfirmPay} modalVisible={showPayType} setModalVisible={setShowPayType} payChoice={payChoice} setPayChoice={setPayChoice} /> */}
@ -306,7 +310,7 @@ export default function Rights() {
</View>
{/* 协议弹窗 */}
<PrivacyModal modalVisible={showTerms} setModalVisible={setShowTerms} type={"member"} />
<PrivacyModal modalVisible={showTerms} setModalVisible={setShowTerms} type={"membership"} />
</View>
);
}
@ -455,6 +459,3 @@ const styles = StyleSheet.create({
lineHeight: 32
}
});
function validateAndGrantPurchase(purchase: ProductPurchase) {
throw new Error('Function not implemented.');
}

View File

@ -11,7 +11,6 @@ interface Props {
premiumPay: any;
loading: boolean;
setShowTerms: (visible: boolean) => void;
restorePurchases: () => void;
}
export interface PayItem {
@ -31,7 +30,7 @@ export interface PayItem {
}
const Premium = (props: Props) => {
const { style, payType, setPayType, premiumPay, loading, setShowTerms, restorePurchases } = props;
const { style, payType, setPayType, premiumPay, loading } = props;
const bestValue = maxDiscountProduct(premiumPay)?.product_code
const { t } = useTranslation();
@ -80,7 +79,7 @@ const Premium = (props: Props) => {
})
}
</ScrollView>
<View style={{ flexDirection: 'row', gap: 8, marginLeft: 4, marginTop: 8 }}>
{/* <View style={{ flexDirection: 'row', gap: 8, marginLeft: 4, marginTop: 8 }}>
<ThemedText style={{ color: '#AC7E35', fontSize: 10 }}>
{t('personal:rights.restorePurchase')}
</ThemedText>
@ -89,7 +88,7 @@ const Premium = (props: Props) => {
{t('personal:rights.restore')}
</ThemedText>
</TouchableOpacity>
</View>
</View> */}
</View>
);
}