anln_0000001_2.1 ()

Co-authored-by: al <al@cdhncy.com>
Reviewed-on: https://git.wishpal.cn/wishpal_ironfan/tiefen_space_app/pulls/34
This commit is contained in:
yezian 2025-03-17 20:43:43 +08:00
parent 37e5aba29a
commit 8fe9424b62
20 changed files with 1321 additions and 452 deletions
.env
assets/images
package.json
screeens
CreateSpace
Login
PasswordLogin
PhoneNumLogin
Messages/MessageDetail
components
AutoAnswerBtn
OwnBubble
index.jsx
My
NoticeDetail/components/MessageList
Refund/RefundList
PendingReview
Reviewed
index.jsx
Search/HostList
Space/SpaceList
SpaceIntroduce
SpaceSetting/SpacePaymentSetting
StreamerSpace
yarn.lock

3
.env
View File

@ -1,4 +1,5 @@
EXPO_PUBLIC_API_URL=https://api.tiefen.space
EXPO_PUBLIC_RSA_KEY=-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMXPIjKV6CMi5O9tIXJWNIfnqXjqOZ1KmRByRAP073DU+gzMLygzEsrztJzbz/K/Julkz6XhheZ8vdz+boAl1HsCAwEAAQ==-----END PUBLIC KEY-----
EXPO_PUBLIC_WEB_URL=https://tiefen.space
EXPO_PUBLIC_WEBSOCKET_URL=wss://ws.tiefen.space
EXPO_PUBLIC_WEBSOCKET_URL=wss://ws.tiefen.space
EXPO_PUBLIC_WEB_ASSETS_URL=https://levianderwinv01.tiefen.space/web_app_public

BIN
assets/images/newM.png Normal file

Binary file not shown.

After

(image error) Size: 100 KiB

View File

@ -67,6 +67,7 @@
"react-native-gesture-handler": "~2.16.1",
"react-native-gifted-chat": "^2.4.0",
"react-native-image-zoom-viewer": "^3.0.1",
"react-native-modal": "^13.0.1",
"react-native-pager-view": "6.3.0",
"react-native-parsed-text": "^0.0.22",
"react-native-picker-select": "^8.1.0",

View File

@ -6,8 +6,9 @@ import {
TextInput,
KeyboardAvoidingView,
Platform,
TouchableOpacity,
} from "react-native";
import React, { useState } from "react";
import React, { useState, useRef, useMemo } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
@ -15,12 +16,133 @@ import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
import { Button, Divider, CheckBox, Switch } from "@rneui/themed";
const superSingles = [
{ key: 0, index: 0, text: "永久" },
{ key: 4, index: 1, text: "按年生效" },
{ key: 3, index: 2, text: "按半年生效" },
{ key: 2, index: 3, text: "按季度生效" },
{ key: 1, index: 4, text: "按月生效" },
];
const ListItemWithCheckbox = ({
superSingle,
superSinglesContr,
setSuperSinglesContr,
superSingleCheckeds,
setSuperSingleCheckeds,
index,
}) => {
const tailwind = useTailwind();
return (
<View style={tailwind("mt-4")}>
<View>
<View style={tailwind("flex-row items-center")}>
<CheckBox
checked={superSingleCheckeds.includes(index)}
onPress={(e) => {
e.stopPropagation();
const newSuperSinglesContr = [...superSinglesContr];
newSuperSinglesContr[index].enable =
!superSingleCheckeds.includes(index);
// newSuperSinglesContr[index].price = "0";
// newSuperSinglesContr[index].wechatFree = false;
setSuperSinglesContr(newSuperSinglesContr);
if (superSingleCheckeds.includes(index)) {
setSuperSingleCheckeds(() => {
const newSuperSingleCheckeds = [...superSingleCheckeds];
newSuperSingleCheckeds.splice(
newSuperSingleCheckeds.indexOf(index),
1
);
return newSuperSingleCheckeds;
});
} else {
setSuperSingleCheckeds(superSingleCheckeds.concat(index));
}
}}
// checkedIcon="dot-circle-o"
// uncheckedIcon="circle-o"
iconType="ionicon"
checkedIcon="checkmark-circle"
uncheckedIcon="ellipse-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={24}
></CheckBox>
<Text style={tailwind("ml-1 text-white")}>{superSingle.text}</Text>
</View>
<View
// className={`mt-2 px-4 h-12 py-3 rounded-[0.8rem] bg-[#FFFFFF1a] flex justify-between items-center ${
// superSingleCheckeds != index
// ? "mt-0 px-0 py-0 hidden"
// : ""
// }`}
style={tailwind(
`mt-2 px-4 h-12 py-3 rounded-lg bg-[#FFFFFF1A] flex-row justify-between items-center ${
!superSingleCheckeds.includes(index) ? "mt-0 p-0 hidden" : ""
}`
)}
>
<View style={tailwind("flex-row items-center")}>
<Text style={tailwind("mr-2 text-[#FFFFFF80] text-sm")}>¥</Text>
<TextInput
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
keyboardType="numeric"
value={superSinglesContr[index].price}
onChangeText={(value) => {
const newSuperSinglesContr = [...superSinglesContr];
newSuperSinglesContr[index].price = value;
setSuperSinglesContr(newSuperSinglesContr);
}}
style={{
...tailwind("text-2xl text-white"),
// maxWidth: 200,
minWidth: 150,
}}
/>
</View>
<View style={tailwind("flex-row items-center")}>
<Text style={tailwind("text-[#FFFFFF80] mr-2")}>|</Text>
<CheckBox
block
checked={superSinglesContr[index].wechatFree}
onPress={() => {
const newSuperSinglesContr = [...superSinglesContr];
newSuperSinglesContr[index].wechatFree =
!newSuperSinglesContr[index].wechatFree;
setSuperSinglesContr(newSuperSinglesContr);
}}
iconType="ionicon"
checkedIcon="checkmark-circle"
uncheckedIcon="ellipse-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={20}
></CheckBox>
<Text style={tailwind("ml-1 text-sm text-white")}>赠送微信</Text>
</View>
</View>
</View>
</View>
);
};
export default function CreateSpace({ navigation, route }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const spacePriceRef = useRef(null);
const ironFanPriceRef = useRef(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const [superSingleCheckeds, setSuperSingleCheckeds] = useState([]);
const [openSuper, setOpenSuper] = useState(true);
const [superSinglesContr, setSuperSinglesContr] = useState([
{ enable: false, price: "0", wechatFree: false, key: 0 },
{ enable: false, price: "0", wechatFree: false, key: 4 },
{ enable: false, price: "0", wechatFree: false, key: 3 },
{ enable: false, price: "0", wechatFree: false, key: 2 },
{ enable: false, price: "0", wechatFree: false, key: 1 },
]);
//
const [spaceIntro, setSpaceIntro] = useState();
@ -42,8 +164,33 @@ export default function CreateSpace({ navigation, route }) {
//
const [unlockWechat, setUnlockWechat] = useState(false);
const [spacePriceAble, setSpacePriceAble] = useState(false);
const listItemWithCheckboxMemo = useMemo(() => {
return superSingles.map((item, index) => (
<View key={item.key}>
<ListItemWithCheckbox
superSingle={item}
superSinglesContr={superSinglesContr}
setSuperSinglesContr={setSuperSinglesContr}
// superSingleCheckeds={superSingleChecked}
superSingleCheckeds={superSingleCheckeds}
setSuperSingleCheckeds={setSuperSingleCheckeds}
index={index}
/>
</View>
));
}, [superSingleCheckeds, superSinglesContr]);
const handleSubmit = async () => {
if (!spaceIntro || !spacePrice || !ironFanPrice) {
const superSingle = [...superSinglesContr];
const openSuperEveryFalse = Object.values(superSingle).every(
(it) => !it.enable
);
if (
!spaceIntro ||
!spacePrice ||
!ironFanPrice ||
(openSuper && openSuperEveryFalse)
) {
Toast.show({
type: "error",
text1: "请完善内容后提交",
@ -51,16 +198,8 @@ export default function CreateSpace({ navigation, route }) {
});
return;
}
if (isSuperFanOn && !superFanPrice) {
Toast.show({
type: "error",
text1: "请填写超粉价格",
topOffset: 60,
});
return;
}
const _spacePrice = parseInt(spacePrice * 100, 10);
if (isNaN(_spacePrice) || _spacePrice < 0) {
if (isNaN(_spacePrice) || _spacePrice < 0 || _spacePrice > 388800) {
Toast.show({
type: "error",
text1: "请输入有效的解锁空间价格",
@ -77,32 +216,60 @@ export default function CreateSpace({ navigation, route }) {
});
return;
}
const _superFanPrice = parseInt(superFanPrice * 100, 10);
if (
isSuperFanOn &&
(isNaN(_superFanPrice) || _superFanPrice < 100 || _superFanPrice > 388800)
) {
Toast.show({
type: "error",
text1: "请输入有效的超粉价格",
topOffset: 60,
let isPrice = false;
if (openSuper) {
Object.values(superSingle).forEach((it) => {
if (it.enable) {
const superFanPrice = it.price;
if (!superFanPrice) {
Toast.show({
type: "error",
text1: "请填写超粉价格",
topOffset: 60,
});
isPrice = true;
return;
} else {
const _superFanPrice = parseInt(superFanPrice * 100, 10);
if (
openSuper &&
(isNaN(_superFanPrice) ||
_superFanPrice < 100 ||
_superFanPrice > 388800)
) {
isPrice = true;
Toast.show({
type: "error",
text1: "请输入有效的超粉价格",
topOffset: 60,
});
return;
}
if (openSuper && _superFanPrice <= _ironFanPrice) {
isPrice = true;
Toast.show({
type: "error",
text1: "请输入大于铁粉价格的超粉价格",
topOffset: 60,
});
return;
}
}
}
});
return;
}
if (isSuperFanOn && _superFanPrice <= _ironFanPrice) {
Toast.show({
type: "error",
text1: "请输入大于铁粉价格的超粉价格",
topOffset: 60,
});
return;
}
if (isPrice) return;
if (isSubmitting) return;
setIsSubmitting(true);
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const superfan_price_list = superSingle.map((it, index) => ({
period: index,
enable: it.enable ? 1 : 0,
price: parseInt(it.price * 100, 10),
is_superfanship_give_wechat: it.wechatFree ? 1 : 0,
}));
try {
const base = await baseRequest();
const body = {
@ -110,9 +277,10 @@ export default function CreateSpace({ navigation, route }) {
admission_price: parseInt(spacePrice * 100, 10),
ironfanship_price: parseInt(ironFanPrice * 100, 10),
is_superfanship_enabled: isSuperFanOn ? 1 : 0,
superfanship_price: parseInt(superFanPrice * 100, 10),
superfanship_valid_period: superFanExpiration,
is_superfanship_give_wechat: unlockWechat ? 1 : 0,
// superfanship_price: parseInt(superFanPrice * 100, 10),
// superfanship_valid_period: superFanExpiration,
// is_superfanship_give_wechat: unlockWechat ? 1 : 0,
superfan_price_list,
...base,
};
const signature = await generateSignature(body);
@ -172,217 +340,123 @@ export default function CreateSpace({ navigation, route }) {
"h-32 bg-[#FFFFFF1A] text-white rounded-2xl mt-2 p-2"
)}
/>
<View style={tailwind("flex flex-row items-center justify-between")}>
<Text
style={tailwind("text-base font-medium text-white mt-4 mb-1")}
<View style={tailwind("mt-4")}>
<View
style={tailwind("flex flex-row justify-between items-center")}
>
<Text style={tailwind("text-[#F53030]")}>*</Text>解锁空间价格
</Text>
<Text
style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-4 mb-1")}
>
¥0~3888仅支持整数
</Text>
</View>
<TextInput
value={spacePrice}
onChangeText={(value) => setSpacePrice(value)}
keyboardType="numeric"
placeholder="解锁后可查看空间内免费动态"
placeholderTextColor="#FFFFFF80"
style={tailwind("text-white")}
underlineColorAndroid="transparent"
textAlign="top"
/>
<Divider style={tailwind("my-2")} />
<View style={tailwind("flex flex-row items-center justify-between")}>
<Text
style={tailwind("text-base font-medium text-white mt-4 mb-1")}
>
<Text style={tailwind("text-[#F53030]")}>*</Text>铁粉价格
</Text>
<Text
style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-4 mb-1")}
>
¥1~3888仅支持整数
</Text>
</View>
<TextInput
value={ironFanPrice}
onChangeText={(value) => setIronFanPrice(value)}
keyboardType="numeric"
placeholder="解锁后可查看空间内铁粉专享动态"
placeholderTextColor="#FFFFFF80"
style={tailwind("text-white")}
underlineColorAndroid="transparent"
textAlign="top"
/>
<Divider style={tailwind("my-2")} />
<View
style={tailwind(
"flex flex-row items-center justify-between mt-4 mb-1"
)}
>
<Text style={tailwind("text-base font-medium text-white")}>
<Text style={tailwind("text-[#F53030]")}>*</Text>启用超粉功能
</Text>
<Switch
value={isSuperFanOn}
onValueChange={(value) => setIsSuperFanOn(value)}
thumbColor="#ffffff"
trackColor={{ true: "#FF669E", false: "#FFFFFF1A" }}
style={tailwind("mx-1")}
/>
</View>
<Divider style={tailwind("my-2")} />
{isSuperFanOn && (
<View>
<View
style={tailwind("flex flex-row items-center justify-between")}
>
<Text
style={tailwind("text-base font-medium text-white mt-4 mb-1")}
>
超粉价格
</Text>
<Text
style={tailwind(
"text-sm font-medium text-[#FFFFFF80] mt-4 mb-1"
)}
>
¥1~3888仅支持整数
</Text>
<View style={tailwind("flex-row text-sm")}>
<Text style={tailwind("text-white")}>解锁空间价格</Text>
<Text style={tailwind("text-[#F53030]")}>*</Text>
</View>
<TextInput
value={superFanPrice}
onChangeText={(value) => setSuperFanPrice(value)}
keyboardType="numeric"
placeholder="最高身份,可查看空间所有动态"
placeholderTextColor="#FFFFFF80"
style={tailwind("text-white")}
underlineColorAndroid="transparent"
textAlign="top"
/>
<Divider style={tailwind("my-2")} />
<Text
style={tailwind("text-base font-medium text-white mt-4 mb-1")}
>
超粉单次开通有效期
<Text style={tailwind("text-white text-xs")}>
成为空间成员可查看免费帖
</Text>
<View style={tailwind("flex flex-row flex-wrap")}>
<View style={tailwind("flex flex-row basis-1/3 items-center")}>
<CheckBox
checked={superFanExpiration === 0}
onPress={() => setSuperFanExpiration(0)}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={18}
/>
<Text
onPress={() => setSuperFanExpiration(0)}
style={tailwind("text-base font-medium text-white")}
>
永久
</Text>
</View>
<View style={tailwind("flex flex-row basis-1/3 items-center")}>
<CheckBox
checked={superFanExpiration === 4}
onPress={() => setSuperFanExpiration(4)}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={18}
/>
<Text
onPress={() => setSuperFanExpiration(4)}
style={tailwind("text-base font-medium text-white")}
>
年度
</Text>
</View>
<View style={tailwind("flex flex-row basis-1/3 items-center")}>
<CheckBox
checked={superFanExpiration === 3}
onPress={() => setSuperFanExpiration(3)}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={18}
/>
<Text
onPress={() => setSuperFanExpiration(3)}
style={tailwind("text-base font-medium text-white")}
>
半年
</Text>
</View>
<View
style={tailwind("flex flex-row basis-1/3 items-center mt-2")}
>
<CheckBox
checked={superFanExpiration === 2}
onPress={() => setSuperFanExpiration(2)}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={18}
/>
<Text
onPress={() => setSuperFanExpiration(2)}
style={tailwind("text-base font-medium text-white")}
>
季度
</Text>
</View>
<View
style={tailwind("flex flex-row basis-1/3 items-center mt-2")}
>
<CheckBox
checked={superFanExpiration === 1}
onPress={() => setSuperFanExpiration(1)}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={18}
/>
<Text
onPress={() => setSuperFanExpiration(1)}
style={tailwind("text-base font-medium text-white")}
>
月度
</Text>
</View>
</View>
<Divider style={tailwind("my-2")} />
<View
style={tailwind(
"flex flex-row items-center justify-between mt-4 mb-1"
)}
>
<Text style={tailwind("text-base font-medium text-white")}>
开通超粉赠送微信
</Text>
<Switch
value={unlockWechat}
onValueChange={(value) => setUnlockWechat(value)}
thumbColor="#ffffff"
trackColor={{ true: "#FF669E", false: "#FFFFFF1A" }}
style={tailwind("mx-1")}
</View>
<TouchableOpacity
onPress={() => {
spacePriceRef.current && spacePriceRef.current.focus();
}}
style={tailwind(
"mt-2 px-4 py-3 h-12 rounded-lg bg-[#FFFFFF1A] flex-row justify-between items-center"
)}
>
<View style={tailwind("flex-row items-center")}>
<Text style={tailwind("text-[#FFFFFF80] text-sm mr-1")}>¥</Text>
<TextInput
ref={spacePriceRef}
focusable={spacePriceAble}
value={spacePrice}
onChangeText={setSpacePrice}
keyboardType="numeric"
placeholder="0~3888仅支持整数"
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
style={{
...tailwind("text-white"),
// maxWidth: 250,
minWidth: 150,
}}
/>
</View>
<Divider style={tailwind("my-2")} />
<View>
<Text style={tailwind("text-[#FFFFFF80] text-xs")}>
点击编辑
</Text>
</View>
</TouchableOpacity>
</View>
<View style={tailwind("my-4")}>
<View
style={tailwind("flex flex-row justify-between items-center")}
>
<View style={tailwind("flex-row text-sm")}>
<Text style={tailwind("text-white")}>铁粉价格</Text>
<Text style={tailwind("text-[#F53030]")}>*</Text>
</View>
<Text style={tailwind("text-white text-xs")}>
累计消费达成后解锁铁粉权益
</Text>
</View>
<TouchableOpacity
onPress={() => {
ironFanPriceRef.current && ironFanPriceRef.current.focus();
}}
style={tailwind(
"mt-2 px-4 py-3 h-12 rounded-lg bg-[#FFFFFF1A] flex-row justify-between items-center"
)}
>
<View style={tailwind("flex-row items-center")}>
<Text style={tailwind("text-[#FFFFFF80] text-sm mr-1")}>¥</Text>
<TextInput
ref={ironFanPriceRef}
value={ironFanPrice}
onChangeText={setIronFanPrice}
keyboardType="numeric"
placeholder="1~3888仅支持整数"
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
style={{
...tailwind("text-white"),
// maxWidth: 250,
minWidth: 150,
}}
/>
</View>
<View>
<Text style={tailwind("text-[#FFFFFF80] text-xs")}>
点击编辑
</Text>
</View>
</TouchableOpacity>
</View>
<View style={tailwind("my-4 flex-row justify-between items-center")}>
<View style={tailwind("text-sm")}>
<Text style={tailwind("text-white")}>超粉功能</Text>
</View>
<View style={tailwind("flex-row items-center")}>
<Text style={tailwind("text-white text-xs mr-2")}>是否启用</Text>
<View>
<Switch
value={openSuper}
onValueChange={(value) => setOpenSuper(value)}
thumbColor="#ffffff"
trackColor={{ true: "#FF669E", false: "#FFFFFF1A" }}
/>
</View>
</View>
</View>
{openSuper && (
<View style={tailwind("mt-4")}>
<View style={tailwind("flex-row justify-between items-center")}>
<View style={tailwind("flex-row items-center text-sm")}>
<Text style={tailwind("text-white")}>超粉单次开通类型</Text>
<Text style={tailwind("text-[#F53030]")}>*</Text>
</View>
<Text style={tailwind("text-white text-xs")}>
付费后解锁对应期限超粉权益
</Text>
</View>
<View>{listItemWithCheckboxMemo}</View>
</View>
)}
<Button

View File

@ -1,4 +1,4 @@
import { View, Text, TextInput } from "react-native";
import { View, Text, TextInput, TouchableOpacity } from "react-native";
import React, { useState, useContext, useEffect } from "react";
import { useTailwind } from "tailwind-rn";
import { Button, CheckBox } from "@rneui/themed";
@ -11,6 +11,9 @@ import MyDivider from "../../../components/MyDivider";
import baseRequest from "../../../utils/baseRequest";
import { get, save, storeAppInfo } from "../../../utils/storeInfo";
import MyModal from "../../../components/MyModal";
import Modal from "react-native-modal";
import { WebView } from "react-native-webview";
import { Icon } from "@rneui/themed";
export default function PasswordLogin() {
const { signIn, checked, setChecked } = useContext(AuthContext);
const navigation = useNavigation();
@ -24,7 +27,41 @@ export default function PasswordLogin() {
const [mobilePhone, setMobilePhone] = useState("");
const [password, setPassword] = useState("");
const [isModalVisible, setIsModalVisible] = useState(false);
//Modal
const [popVisible, setPopVisible] = useState({
visible: false,
data: {
title: "",
uri: "",
},
});
//cookies
const [cookies, setCookies] = useState();
const setCookieScript = `
document.cookie = "b_mid=${cookies?.b_mid} ;";
document.cookie = "b_did=${cookies?.b_did} ;";
document.cookie = "b_ver=${cookies?.b_ver} ;";
document.cookie = "b_dt=${cookies?.b_dt} ;";
document.cookie = "b_model=${cookies?.b_model} ;";
document.cookie = "b_nt=${cookies?.b_nt} ;";
document.cookie = "b_token=${cookies?.b_token} ;";
true;
`;
useEffect(() => {
async function getCookies() {
const base = await baseRequest();
setCookies({
b_mid: base.b_mid,
b_did: base.b_did,
b_ver: base.b_ver,
b_dt: base.b_dt,
b_model: base.b_model,
b_nt: base.b_nt,
b_token: base.b_token,
});
}
getCookies();
}, []);
//
useEffect(() => {
async function getMobilePhone() {
@ -193,24 +230,30 @@ export default function PasswordLogin() {
<Text style={tailwind("text-[#FFFFFF80] font-medium text-xs")}>
我已阅读并同意
<Text
onPress={() =>
navigation.navigate("WebWithHeader", {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
})
}
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
},
});
}}
style={tailwind("text-[#FF669E] text-xs")}
>
用户协议
</Text>
<Text
onPress={() =>
navigation.navigate("WebWithHeader", {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
})
}
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
},
});
}}
style={tailwind("text-[#FF669E] text-xs")}
>
隐私政策
@ -232,7 +275,40 @@ export default function PasswordLogin() {
visible={isModalVisible}
setVisible={setIsModalVisible}
title="登录提示"
content="为了更好保障你的合法权益,请阅读和同意《用户协议》和《隐私政策》。"
content={
<Text style={tailwind("text-[#FFFFFF80] font-medium text-base")}>
为了更好保障你的合法权益请阅读和同意
<Text
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
},
});
}}
style={tailwind("text-[#FF669E] text-base")}
>
用户协议
</Text>
<Text
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
},
});
}}
style={tailwind("text-[#FF669E] text-base")}
>
隐私政策
</Text>
</Text>
}
cancel={() => {
setIsModalVisible(false);
}}
@ -242,6 +318,92 @@ export default function PasswordLogin() {
handleSubmit();
}}
/>
{/* 协议通知弹窗 */}
{popVisible.visible && (
<Modal
isVisible={popVisible.visible}
// swipeDirection={["down"]}
onBackdropPress={() =>
setPopVisible({
visible: false,
data: {
title: "",
uri: "",
},
})
}
animationInTiming={500} //
animationOutTiming={1000} //
animationIn="bounceInUp" //
animationOut="bounceInDown" //
// scrollHorizontal={true}
style={{
height: 120,
paddingBottom: 0,
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
margin: 0,
justifyContent: "flex-end",
}}
>
<View style={tailwind("flex flex-row items-center h-12")}>
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() =>
setPopVisible({
visible: false,
data: {
title: "",
uri: "",
},
})
}
/>
<Text style={tailwind("text-base font-medium text-white")}>
{popVisible.data.title}
</Text>
</View>
<View
style={{
...tailwind("w-full"),
backgroundColor: "#17161A",
paddingBottom: 20,
height: 620,
}}
>
<WebView
incognito
source={{
uri: popVisible.data.uri,
}}
userAgent="FromWebview"
// onMessage={async (event) => {
// const msg = JSON.parse(event.nativeEvent.data);
// if (msg.type === "SAVE_IMAGE") {
// saveImage(msg.data);
// } else if (msg.type === "COPY_URL") {
// copy(msg.data);
// } else if (msg.type === "NAVIGATE") {
// navigation.navigate(msg.data.page, { ...msg.data.params });
// } else if (msg.type === "OPEN_BROWSER") {
// openBrowser(msg.data);
// }
// }}
injectedJavaScript={setCookieScript}
originWhitelist={[
"https://*",
"http://*",
"alipays://*",
"alipay://*",
"weixin://*",
]}
/>
</View>
</Modal>
)}
</View>
);
}

View File

@ -10,7 +10,10 @@ import MyDivider from "../../../components/MyDivider";
import baseRequest from "../../../utils/baseRequest";
import { get, save, storeAppInfo } from "../../../utils/storeInfo";
import { generateSignature } from "../../../utils/crypto";
import Modal from "react-native-modal";
import { WebView } from "react-native-webview";
import { Icon } from "@rneui/themed";
import MyModal from "../../../components/MyModal";
export default function PhoneNumLogin() {
const { signIn, inviterCode, checked, setChecked } = useContext(AuthContext);
const navigation = useNavigation();
@ -25,7 +28,42 @@ export default function PhoneNumLogin() {
const [regionCode, setRegionCode] = useState("86");
const [mobilePhone, setMobilePhone] = useState("");
const [veriCode, setVeriCode] = useState("");
//Modal
const [popVisible, setPopVisible] = useState({
visible: false,
data: {
title: "",
uri: "",
},
});
//cookies
const [cookies, setCookies] = useState();
const [isModalVisible, setIsModalVisible] = useState(false);
const setCookieScript = `
document.cookie = "b_mid=${cookies?.b_mid} ;";
document.cookie = "b_did=${cookies?.b_did} ;";
document.cookie = "b_ver=${cookies?.b_ver} ;";
document.cookie = "b_dt=${cookies?.b_dt} ;";
document.cookie = "b_model=${cookies?.b_model} ;";
document.cookie = "b_nt=${cookies?.b_nt} ;";
document.cookie = "b_token=${cookies?.b_token} ;";
true;
`;
useEffect(() => {
async function getCookies() {
const base = await baseRequest();
setCookies({
b_mid: base.b_mid,
b_did: base.b_did,
b_ver: base.b_ver,
b_dt: base.b_dt,
b_model: base.b_model,
b_nt: base.b_nt,
b_token: base.b_token,
});
}
getCookies();
}, []);
//
useEffect(() => {
async function getMobilePhone() {
@ -101,30 +139,14 @@ export default function PhoneNumLogin() {
//
const handleSubmit = async () => {
if (!checked) {
Toast.show({
type: "error",
text1: "请先阅读并同意《用户协议》和《隐私政策》后登录",
topOffset: 60,
});
return;
}
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
Toast.show({
type: "error",
text1: "手机号码格式错误",
topOffset: 60,
});
return;
}
if (!veriCode) {
Toast.show({
type: "error",
text1: "请输入验证码",
topOffset: 60,
});
return;
}
// if (!checked) {
// Toast.show({
// type: "error",
// text1: "",
// topOffset: 60,
// });
// return;
// }
//app
await storeAppInfo();
//RSA
@ -194,6 +216,31 @@ export default function PhoneNumLogin() {
console.error(error);
}
};
//
const handleCheck = async () => {
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
Toast.show({
type: "error",
text1: "手机号码格式错误",
topOffset: 60,
});
return;
}
if (!veriCode) {
Toast.show({
type: "error",
text1: "请输入验证码",
topOffset: 60,
});
return;
}
//
if (!checked) {
setIsModalVisible(true);
return;
}
handleSubmit();
};
return (
<View style={tailwind("mt-14 flex-1 flex-col")}>
<View style={tailwind("flex px-10 justify-center")}>
@ -259,24 +306,30 @@ export default function PhoneNumLogin() {
<Text style={tailwind("text-[#FFFFFF80] font-medium text-xs")}>
我已阅读并同意
<Text
onPress={() =>
navigation.navigate("WebWithHeader", {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
})
}
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
},
});
}}
style={tailwind("text-[#FF669E] text-xs")}
>
用户协议
</Text>
<Text
onPress={() =>
navigation.navigate("WebWithHeader", {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
})
}
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
},
});
}}
style={tailwind("text-[#FF669E] text-xs")}
>
隐私政策
@ -287,13 +340,146 @@ export default function PhoneNumLogin() {
color="#FF669E"
radius="999"
size="md"
onPress={handleSubmit}
onPress={handleCheck}
titleStyle={tailwind("text-base font-medium")}
containerStyle={tailwind("mt-2")}
>
登录
</Button>
</View>
<MyModal
visible={isModalVisible}
setVisible={setIsModalVisible}
title="登录提示"
content={
<Text style={tailwind("text-[#FFFFFF80] font-medium text-base")}>
为了更好保障你的合法权益请阅读和同意
<Text
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "用户协议",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
},
});
}}
style={tailwind("text-[#FF669E] text-base")}
>
用户协议
</Text>
<Text
onPress={() => {
setPopVisible({
visible: true,
data: {
title: "隐私政策",
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
},
});
}}
style={tailwind("text-[#FF669E] text-base")}
>
隐私政策
</Text>
</Text>
}
cancel={() => {
setIsModalVisible(false);
}}
confirm={() => {
setIsModalVisible(false);
toggleCheckbox();
handleSubmit();
}}
/>
{/* 协议通知弹窗 */}
{popVisible.visible && (
<Modal
isVisible={popVisible.visible}
// swipeDirection={["down"]}
onBackdropPress={() =>
setPopVisible({
visible: false,
data: {
title: "",
uri: "",
},
})
}
animationInTiming={500} //
animationOutTiming={1000} //
animationIn="bounceInUp" //
animationOut="bounceInDown" //
// scrollHorizontal={true}
style={{
height: 120,
paddingBottom: 0,
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
margin: 0,
justifyContent: "flex-end",
}}
>
<View style={tailwind("flex flex-row items-center h-12")}>
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() =>
setPopVisible({
visible: false,
data: {
title: "",
uri: "",
},
})
}
/>
<Text style={tailwind("text-base font-medium text-white")}>
{popVisible.data.title}
</Text>
</View>
<View
style={{
...tailwind("w-full"),
backgroundColor: "#17161A",
paddingBottom: 20,
height: 620,
}}
>
<WebView
incognito
source={{
uri: popVisible.data.uri,
}}
userAgent="FromWebview"
// onMessage={async (event) => {
// const msg = JSON.parse(event.nativeEvent.data);
// if (msg.type === "SAVE_IMAGE") {
// saveImage(msg.data);
// } else if (msg.type === "COPY_URL") {
// copy(msg.data);
// } else if (msg.type === "NAVIGATE") {
// navigation.navigate(msg.data.page, { ...msg.data.params });
// } else if (msg.type === "OPEN_BROWSER") {
// openBrowser(msg.data);
// }
// }}
injectedJavaScript={setCookieScript}
originWhitelist={[
"https://*",
"http://*",
"alipays://*",
"alipay://*",
"weixin://*",
]}
/>
</View>
</Modal>
)}
</View>
);
}

View File

@ -0,0 +1,34 @@
import { View, Text } from "react-native";
import React, { useState, useCallback, useEffect } from "react";
import {
GestureHandlerRootView,
TouchableOpacity,
} from "react-native-gesture-handler";
export default function AutoAnswerBtn({ onSend, text }) {
return (
<TouchableOpacity
onPress={() => {
// console.log("log", item);
onSend([{ text }]);
}}
style={{
// ...tailwind("border rounded text-center px-4 py-1"),
backgroundColor: "#3333331A",
// borderWidth: 1,
// borderColor: "black",
borderRadius: 10,
padding: 6,
}}
>
<View
style={{
paddingHorizontal: 10,
// height: 60,
overflow: "hidden",
}}
>
<Text>{text}</Text>
</View>
</TouchableOpacity>
);
}

View File

@ -0,0 +1,109 @@
import { View, Text } from "react-native";
import React, { useState, useCallback, useEffect } from "react";
import { Bubble } from "react-native-gifted-chat";
import { useTailwind } from "tailwind-rn";
import "dayjs/locale/zh-cn";
import {
GestureHandlerRootView,
TouchableOpacity,
} from "react-native-gesture-handler";
import AutoAnswerBtn from "../AutoAnswerBtn";
export default function OwnBubble({
navigation,
route,
onSend,
currentMessage,
...props
}) {
const tailwind = useTailwind();
const [currentHeight, setCurrentHeight] = useState(null);
return (
<Bubble
{...props}
height={currentHeight}
wrapperStyle={{
left: {
...tailwind("bg-white p-1"),
minHeight: currentHeight,
// width: 100,
flexShrink: 1,
flexGrow: 0,
// position: "relative", // absolute
overflow: "hidden", //
// justifyContent: "center",
// height: "auto",
},
right: {
...tailwind("p-1"),
// minHeight: currentHeight,
},
}}
currentMessage={{
...currentMessage,
text:
currentMessage.mType === 1 ? (
<View
style={{ flexShrink: 1 }} //
onLayout={(event) => {
const { height } = event.nativeEvent.layout;
//
// console.log(":", height, currentMessage._id);
//
// props.onLayout({ height });
setCurrentHeight((prev) => height);
// currentOwnHeight = height;
//
}}
>
{/* <Text>{currentMessage.text}</Text> */}
<AutoMessage
{...props}
message={currentMessage.text}
messageData={currentMessage}
mType={currentMessage.mType}
height={currentHeight}
onSend={onSend}
/>
</View>
) : (
currentMessage.text
),
}}
/>
);
}
const AutoMessage = ({
message = "",
mType,
height,
currentMessage,
...props
}) => {
// console.log("data", height);
const tailwind = useTailwind();
const test = message.split("|");
const btns = test[1].split(",");
return (
<View
{...props}
style={{ marginTop: height, paddingVertical: 10, width: 200 }}
>
<View style={{ marginTop: 10 }}>
<Text style={{ fontSize: 16 }}>{test[0]}</Text>
</View>
<View
style={{
...tailwind("flex-row flex-wrap mt-2"),
gap: 8,
}}
>
{btns.map((item, index) => {
return <AutoAnswerBtn key={index} text={item} {...props} />;
})}
</View>
</View>
);
// data.m_type===1?it?.text.split("|")it?.text
};

View File

@ -5,7 +5,6 @@ import {
Send,
InputToolbar,
Composer,
Bubble,
Day,
LoadEarlier,
} from "react-native-gifted-chat";
@ -17,6 +16,8 @@ import { Image } from "expo-image";
import { get } from "../../../utils/storeInfo";
import Toast from "react-native-toast-message";
import requireAPI from "../../../utils/requireAPI";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import OwnBubble from "./components/OwnBubble";
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
/*
@ -25,13 +26,12 @@ params格式
mid: item.mid,
}
*/
export default function MessageDetail({ navigation, route }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const params = route.params;
const [messages, setMessages] = useState([]);
const [currentHeight, setCurrentHeight] = useState(null);
//
const [selfData, setSelfData] = useState({});
useEffect(() => {
@ -68,12 +68,12 @@ export default function MessageDetail({ navigation, route }) {
return;
}
navigation.setOptions({
title: detailData.data.streamer_ext.name,
title: _data.data.streamer_ext.name,
});
await sendAutoMessages(
detailData.data.streamer_ext?.name,
detailData.data.streamer_ext?.avatar?.images[0]?.urls[0],
detailData.data.streamer_ext?.auto_response_message
_data.data.streamer_ext?.name,
_data.data.streamer_ext?.avatar?.images[0]?.urls[0],
_data.data.streamer_ext?.auto_response_message
);
} catch (error) {
console.error(error);
@ -95,6 +95,7 @@ export default function MessageDetail({ navigation, route }) {
_id: 1,
text: content,
createdAt: new Date(),
user: {
_id: 1,
name: name,
@ -205,6 +206,7 @@ export default function MessageDetail({ navigation, route }) {
_id: item.id,
createdAt: new Date(item.ct * 1000).toISOString(),
text: item.message,
mType: item.m_type,
user: {
_id: account?.mid,
name: account?.name,
@ -216,6 +218,7 @@ export default function MessageDetail({ navigation, route }) {
_id: item.id,
createdAt: new Date(item.ct * 1000).toISOString(),
text: item.message,
mType: item.m_type,
user: {
_id: 0,
name: "客服",
@ -257,6 +260,7 @@ export default function MessageDetail({ navigation, route }) {
_id: item.id,
createdAt: new Date(item.ct * 1000).toISOString(),
text: item.message,
mType: item.m_type,
user: {
_id: account.mid,
name: account.name,
@ -268,6 +272,7 @@ export default function MessageDetail({ navigation, route }) {
_id: item.id,
createdAt: new Date(item.ct * 1000).toISOString(),
text: item.message,
mType: item.m_type,
user: {
_id: 1,
name: "客服",
@ -280,6 +285,11 @@ export default function MessageDetail({ navigation, route }) {
if (prev[0]?._id === temMessages[0]?._id) {
return prev;
} else {
// console.log("temMessages", temMessages, "prev", prev);
const newMessages = [...temMessages, ...prev].filter(
(item, index, self) =>
index === self.findIndex((t) => t.id === item.id)
);
return [...temMessages, ...prev];
}
});
@ -450,17 +460,12 @@ export default function MessageDetail({ navigation, route }) {
}, []);
//
const renderBubble = useCallback((props) => {
return (
<Bubble
{...props}
wrapperStyle={{
left: tailwind("bg-white p-1"),
right: tailwind("p-1"),
}}
/>
);
}, []);
const renderBubble = useCallback(
(props) => {
return <OwnBubble {...props} />;
},
[currentHeight, sessionId]
);
//
const renderLoadEarlier = useCallback(
@ -485,37 +490,43 @@ export default function MessageDetail({ navigation, route }) {
...tailwind("flex-1 bg-[#13121F]"),
}}
>
<View style={tailwind("flex-1")}>
<GiftedChat
placeholder={params?.mid === 1 ? "输入新消息" : "爱就大胆说出来!"}
alwaysShowSend
locale={"zh-cn"}
keyboardShouldPersistTaps="never"
alignTop={false}
listViewProps={{
contentContainerStyle: { flexGrow: 1, justifyContent: "flex-end" },
}}
onLoadEarlier={() => loadEarlierHistory()}
showUserAvatar
showAvatarForEveryMessage
renderAvatarOnTop
messagesContainerStyle={tailwind("bg-[#13121F] pb-4")}
renderAvatar={renderAvatar}
renderDay={renderDay}
renderInputToolbar={renderInputToolbar}
renderBubble={renderBubble}
loadEarlier
renderLoadEarlier={renderLoadEarlier}
renderTime={renderTime}
messages={messages}
onSend={(messages) => onSend(messages)}
user={{
_id: selfData?.mid,
name: selfData?.name,
avatar: selfData?.avatar?.images[0]?.urls[0],
}}
/>
</View>
<GestureHandlerRootView>
<View style={tailwind("flex-1")}>
<GiftedChat
placeholder={params?.mid === 1 ? "输入新消息" : "爱就大胆说出来!"}
alwaysShowSend
locale={"zh-cn"}
keyboardShouldPersistTaps="never"
alignTop={false}
listViewProps={{
contentContainerStyle: {
flexGrow: 1,
justifyContent: "flex-end",
},
}}
onLoadEarlier={() => loadEarlierHistory()}
showUserAvatar
showAvatarForEveryMessage
renderAvatarOnTop
messagesContainerStyle={tailwind("bg-[#13121F] pb-4")}
renderAvatar={renderAvatar}
renderDay={renderDay}
renderInputToolbar={renderInputToolbar}
renderBubble={renderBubble}
// renderMessageText={renderMessageText}
loadEarlier
renderLoadEarlier={renderLoadEarlier}
renderTime={renderTime}
messages={messages}
onSend={(messages) => onSend(messages)}
user={{
_id: selfData?.mid,
name: selfData?.name,
avatar: selfData?.avatar?.images[0]?.urls[0],
}}
/>
</View>
</GestureHandlerRootView>
</View>
);
}

View File

@ -635,9 +635,6 @@ export default function My({ navigation }) {
remainCompleteInformation(() =>
navigation.navigate("Refund", {
screen: "RefundList",
params: {
b_mid: data.mid,
},
})
)
}

View File

@ -234,13 +234,16 @@ const MessageList = ({ navigation, noticeCount, refInstance }) => {
<View
style={tailwind("flex flex-row justify-between items-center flex-1")}
>
<View style={tailwind("flex flex-col")}>
<View style={{ ...tailwind("flex flex-col"), width: "66%" }}>
<View style={tailwind("flex flex-row items-center mb-2")}>
<Text style={tailwind("text-base text-white font-medium mr-2")}>
{title}
</Text>
</View>
<Text style={{ ...tailwind("text-xs"), color: "#FFFFFFB2" }}>
<Text
style={{ ...tailwind("text-xs"), color: "#FFFFFFB2" }}
numberOfLines={1}
>
{subtitle}
</Text>
</View>
@ -369,7 +372,14 @@ const MessageList = ({ navigation, noticeCount, refInstance }) => {
<Text style={tailwind("text-xs text-white")}>官方</Text>
</View>
</View>
<Text style={{ ...tailwind("text-xs"), color: "#FFFFFFB2" }}>
<Text
style={{
...tailwind("text-xs"),
color: "#FFFFFFB2",
paddingRight: 10,
}}
numberOfLines={1}
>
{data?.recent_contact_cs_msg || "暂无新消息"}
</Text>
</View>

View File

@ -9,13 +9,12 @@ import React, { useState } from "react";
import { useTailwind } from "tailwind-rn";
import Toast from "react-native-toast-message";
import Empty from "../../../../components/Empty";
import { ListItem } from "@rneui/themed";
import { ListItem, Button } from "@rneui/themed";
import { Image } from "expo-image";
import baseRequest from "../../../../utils/baseRequest";
import { generateSignature } from "../../../../utils/crypto";
import formatTimestamp from "../../../../utils/formatTimestamp";
export default function PendingReview({ zid, navigation }) {
export default function PendingReview({ navigation }) {
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const tailwind = useTailwind();
@ -23,12 +22,12 @@ export default function PendingReview({ zid, navigation }) {
const [more, setMore] = useState(1);
const [data, setData] = useState({ list: [], total: 0 });
const getData = async () => {
if (zid === undefined || !more) return;
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const b_mid = baseRequest.b_mid;
try {
const base = await baseRequest();
const body = {
b_mid: parseInt(zid),
b_mid: parseInt(b_mid),
audit_type: 1,
offset: offset,
limit: 20,
@ -128,17 +127,18 @@ export default function PendingReview({ zid, navigation }) {
</View>
</View>
</View>
<View style={tailwind("flex-row items-center")}>
<TouchableOpacity
<View style={tailwind("ml-2 flex-row items-center")}>
<Button
onPress={() => {
navigation.navigate("RefundDetail", { id: item.audit_id });
}}
style={tailwind(
"px-4 py-1 rounded-full bg-[#FF669E] flex-row items-center"
)}
titleStyle={tailwind("text-sm font-medium px-2")}
color="#FF669E"
radius="999"
size="md"
>
<Text style={tailwind("text-white text-lg")}>前往审核</Text>
</TouchableOpacity>
前往审核
</Button>
</View>
</View>
</View>

View File

@ -4,31 +4,32 @@ import {
FlatList,
Image as NativeImage,
TouchableOpacity,
Dimensions,
} from "react-native";
import React, { useState } from "react";
import { useTailwind } from "tailwind-rn";
import Toast from "react-native-toast-message";
import Empty from "../../../../components/Empty";
import { ListItem } from "@rneui/themed";
import { ListItem, Icon } from "@rneui/themed";
import { Image } from "expo-image";
import baseRequest from "../../../../utils/baseRequest";
import { generateSignature } from "../../../../utils/crypto";
import formatTimestamp from "../../../../utils/formatTimestamp";
export default function Reviewed({ navigation, zid }) {
export default function Reviewed({ navigation }) {
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const screenWidth = Dimensions.get("window").width;
const tailwind = useTailwind();
const [offset, setOffset] = useState(0);
const [more, setMore] = useState(1);
const [data, setData] = useState({ list: [], total: 0 });
const getData = async () => {
if (zid === undefined || !more) return;
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const b_mid = baseRequest.b_mid;
try {
const base = await baseRequest();
const body = {
b_mid: parseInt(zid),
b_mid: parseInt(b_mid),
audit_type: 2,
offset: offset,
limit: 20,
@ -68,15 +69,24 @@ export default function Reviewed({ navigation, zid }) {
//
const renderItem = ({ item }) => {
return (
<ListItem bottomDivider containerStyle={tailwind("p-0 bg-transparent")}>
<ListItem
bottomDivider
containerStyle={{
...tailwind("p-0 bg-transparent"),
}}
>
<TouchableOpacity
onPress={() =>
navigation.navigate("RefundDetail", { id: item.audit_id })
}
style={tailwind("flex-1")}
>
<View style={tailwind("flex-row justify-between py-3")}>
<View style={tailwind("flex-row")}>
<View
style={{
...tailwind("flex-row justify-between py-3"),
}}
>
<View style={{ ...tailwind("flex-row") }}>
<Image
style={tailwind("w-12 h-12 rounded-full")}
source={item?.account?.avatar?.images[0]?.urls[0]}
@ -87,13 +97,29 @@ export default function Reviewed({ navigation, zid }) {
/>
<View style={tailwind("ml-2 flex-col")}>
<View style={tailwind("flex-row flex-wrap flex-1")}>
<View style={{ width: 100 }}>
<View
style={{
...tailwind("flex-row items-center flex-1"),
// maxWidth: screenWidth - 180,
}}
>
<View
style={
{
// maxWidth: screenWidth - 180 - 90,
}
}
>
<Text
style={tailwind("mr-2 text-base text-white font-medium")}
style={{
...tailwind("mr-2 text-base text-white font-medium"),
width: screenWidth - 180 - 105,
}}
numberOfLines={1}
ellipsizeMode="tail"
>
{item.account.name}
{screenWidth}阿萨德嘎是法国业务
</Text>
</View>
<View style={tailwind("flex-row flex-wrap")}>
@ -117,14 +143,21 @@ export default function Reviewed({ navigation, zid }) {
</View>
<View style={tailwind("flex-row")}>
<View
style={tailwind("bg-[#FFFFFF1A] rounded-full py-0.5 px-2")}
style={tailwind(
"flex-row items-center bg-[#FFFFFF1A] rounded-full py-0.5 px-2"
)}
>
<Icon
type="ionicon"
name="calendar-outline"
size={12}
color="white"
/>
<Text
style={{
...tailwind("text-white text-xs font-medium ml-0.5"),
...tailwind("text-white text-xs font-medium ml-1"),
}}
>
申请时间
{formatTimestamp(item?.refund_t)}
</Text>
</View>

View File

@ -12,7 +12,7 @@ import { TabView, SceneMap, TabBar } from "react-native-tab-view";
import PendingReview from "./PendingReview";
import Reviewed from "./Reviewed";
export default function RefundList({ navigation, route }) {
export default function RefundList({ navigation }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
//tab
@ -25,12 +25,10 @@ export default function RefundList({ navigation, route }) {
const renderScene = useCallback(
SceneMap({
doing: () => (
<PendingReview zid={route.params.b_mid} navigation={navigation} />
),
done: () => <Reviewed zid={route.params.b_mid} navigation={navigation} />,
doing: () => <PendingReview navigation={navigation} />,
done: () => <Reviewed navigation={navigation} />,
}),
[route]
[]
);
const renderIndicator = useCallback((props) => {

View File

@ -107,7 +107,7 @@ export default function HostList() {
type="ionicon"
name="chevron-forward"
size={14}
color="white"
color="#FFFFFF80"
onPress={() => navigation.goBack()}
/>
</TouchableOpacity>

View File

@ -1,5 +1,5 @@
import { View, Text, RefreshControl, TouchableOpacity } from "react-native";
import React, { useState, useCallback } from "react";
import React, { useState, useCallback, useEffect } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
@ -18,23 +18,32 @@ export default function SpaceList() {
const navigation = useNavigation();
const [data, setData] = useState([]);
const getData = async () => {
const [more, setMore] = useState(true);
const [offset, setOffset] = useState(0);
const [currentUserId, setCurrentUserId] = useState(null);
const getData = async (type, offset) => {
if (!more && type !== "top") return;
//
if (data.length === 0 && type === "bottom") return;
if (type === "bottom" && offset === 0) return;
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const userId = await baseRequest();
setCurrentUserId(userId?.b_mid);
try {
const base = await baseRequest();
const signature = await generateSignature({
...base,
});
const _response = await fetch(
`${apiUrl}/api/zone/list_by_visitor_mid?signature=${signature}`,
`${apiUrl}/api/zone/list_by_visitor_mid_v2?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
offset,
limit: 6,
...base,
}),
}
@ -48,13 +57,17 @@ export default function SpaceList() {
});
return;
}
//
if (_data.data.list.length !== 0) {
const finalData = [..._data.data.list, { id: 999999, last: true }];
setData(finalData);
setOffset(_data.data.offset);
setMore(_data.data.more);
if (offset === 0) {
setData(_data.data.list);
return;
}
setData(_data.data.list);
//
setData((prev) => {
return [...prev, ..._data.data.list];
});
} catch (error) {
console.error(error);
}
@ -62,10 +75,15 @@ export default function SpaceList() {
//focus
useFocusEffect(
useCallback(() => {
getData();
(async () => {
const userId = await baseRequest();
if (currentUserId !== userId?.b_mid) {
setCurrentUserId(userId?.b_mid);
getData("top", 0);
}
})();
}, [])
);
const renderItem = ({ item }) => <SpaceCard data={item} />;
//
@ -109,7 +127,7 @@ export default function SpaceList() {
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
setRefreshing(true);
await getData();
await getData("top", 0);
setRefreshing(false);
};
@ -123,12 +141,16 @@ export default function SpaceList() {
>
<View style={tailwind("flex-1 px-2")}>
<FlashList
data={data}
data={data.length === 0 ? [] : [...data, { id: 999999, last: true }]}
keyExtractor={(item) => item.id}
renderItem={renderItem}
estimatedItemSize={166}
initialNumToRender={12}
numColumns={2}
onEndReached={() => {
getData("bottom", offset);
}}
drawDistance={10}
refreshControl={
<RefreshControl
colors={["#FF669E"]}

View File

@ -21,7 +21,7 @@ import { usePreventScreenCapture } from "expo-screen-capture";
import { useFocusEffect } from "@react-navigation/native";
import { useImageViewer } from "../../context/ImageViewProvider";
import MyModal from "../../components/MyModal";
import requireAPI from "../../utils/requireAPI";
export default function SpaceIntroduce({ navigation, route }) {
usePreventScreenCapture();
const tailwind = useTailwind();
@ -72,6 +72,7 @@ export default function SpaceIntroduce({ navigation, route }) {
..._data.data.list[0],
refund_enable: _data.data.refund_enable,
refund_status: _data.data.refund_status,
exit_status: _data.data.exit_status,
});
setIsloading(false);
} catch (error) {
@ -125,6 +126,27 @@ export default function SpaceIntroduce({ navigation, route }) {
console.error(error);
}
};
const handleReenterSpace = async () => {
try {
const body = {
zid: data?.id,
};
const _data = await requireAPI("POST", "/api/zone/exit_reenter", {
body,
});
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
navigation.replace("StreamerSpace", { mid: route.params.mid });
} catch (error) {
// console.error(error);
}
};
//
const [isAddWechatModalVisible, setIsAddWechatModalVisible] = useState(false);
@ -345,7 +367,9 @@ export default function SpaceIntroduce({ navigation, route }) {
>
<TouchableOpacity
onPress={
data?.admission_price === 0
data.exit_status === 1
? handleReenterSpace
: data?.admission_price === 0
? handleJoinFreeSpace
: () => setIsWarnModalVisible(true)
}
@ -353,18 +377,33 @@ export default function SpaceIntroduce({ navigation, route }) {
"flex flex-row items-center justify-center h-12 rounded-full px-10 bg-[#FF669E]"
)}
>
{data?.admission_price !== 0 && (
<NativeImage
style={tailwind("ml-2")}
source={require("../../assets/icon/others/money_pink.png")}
/>
{data?.exit_status === 1 ? (
<>
<Text style={tailwind("text-base text-white font-medium ml-2")}>
已解锁
</Text>
<NativeImage
source={require("../../assets/icon/32DP/link.png")}
/>
</>
) : (
<>
{data?.admission_price !== 0 && (
<NativeImage
style={tailwind("ml-2")}
source={require("../../assets/icon/others/money_pink.png")}
/>
)}
<Text style={tailwind("text-base text-white font-medium ml-2")}>
{data?.admission_price === 0
? "免费加入"
: `${data?.admission_price / 100}元立即加入`}
</Text>
<NativeImage
source={require("../../assets/icon/32DP/link.png")}
/>
</>
)}
<Text style={tailwind("text-base text-white font-medium ml-2")}>
{data?.admission_price === 0
? "免费加入"
: `${data?.admission_price / 100}元立即加入`}
</Text>
<NativeImage source={require("../../assets/icon/32DP/link.png")} />
</TouchableOpacity>
</View>
)}

View File

@ -102,7 +102,7 @@ const ListItemWithCheckbox = ({
setSuperSinglesContr(newSuperSinglesContr);
}}
style={{
...tailwind("text-2xl text-white"),
...tailwind("text-xl text-white"),
// maxWidth: 200,
minWidth: 150,
}}
@ -219,7 +219,7 @@ export default function SpacePaymentSetting({ navigation, route }) {
useEffect(() => {
if (!spacePriceInfo) return;
const { admission_price, ironfanship_price } = spacePriceInfo;
if (admission_price > 0) {
if (admission_price > -1) {
setSpacePrice((admission_price / 100).toString());
}
if (ironfanship_price > 0) {
@ -404,7 +404,7 @@ export default function SpacePaymentSetting({ navigation, route }) {
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
style={{
...tailwind("text-white"),
...tailwind("text-xl text-white"),
// maxWidth: 250,
minWidth: 150,
}}
@ -440,11 +440,11 @@ export default function SpacePaymentSetting({ navigation, route }) {
value={ironFanPrice}
onChangeText={setIronFanPrice}
keyboardType="numeric"
placeholder="0~3888仅支持整数"
placeholder="1~3888仅支持整数"
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
style={{
...tailwind("text-white"),
...tailwind("text-xl text-white"),
// maxWidth: 250,
minWidth: 150,
}}

View File

@ -6,7 +6,7 @@ import {
useWindowDimensions,
Animated,
Easing,
Modal,
Modal as RNModal,
} from "react-native";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { useTailwind } from "tailwind-rn";
@ -29,8 +29,8 @@ import { LinearProgress, Button } from "@rneui/themed";
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 Modal from "react-native-modal";
import requireAPI from "../../utils/requireAPI";
export default function StreamerSpace({ navigation, route }) {
usePreventScreenCapture();
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
@ -44,6 +44,10 @@ export default function StreamerSpace({ navigation, route }) {
//退Modal
const [isRefundingModalVisible, setIsRefundingModalVisible] = useState(false);
//Modal
const [popVisible, setPopVisible] = useState(false);
//
const [noticesMaskInformation, setNoticesMaskInformation] = useState(false);
//
const [data, setData] = useState({});
@ -122,6 +126,7 @@ export default function StreamerSpace({ navigation, route }) {
useEffect(() => {
getData();
getNoticesMaskInformation();
}, []);
//header
@ -138,7 +143,6 @@ export default function StreamerSpace({ navigation, route }) {
),
});
}, [data]);
//
const [isAddWechatModalVisible, setIsAddWechatModalVisible] = useState(false);
@ -168,7 +172,44 @@ export default function StreamerSpace({ navigation, route }) {
}),
[data]
);
const getNoticesMaskInformation = async () => {
const userInfo = await baseRequest();
if (userInfo?.b_mid != params_mid) return;
try {
const data = await requireAPI("POST", "/api/zone/pop_up", {
body: {
mid: params_mid,
},
});
if (data.ret === -1) {
Toast.show({
type: "error",
text1: data.msg,
topOffset: 60,
});
return;
}
setPopVisible(!!data.data.enable);
setNoticesMaskInformation(data.data);
} catch (error) {
// console.error(error);
}
};
//
useEffect(() => {
const unsubscribe = navigation.addListener("state", (e) => {
const state = e.data.state;
const currentRoute = state.routes[state.index];
if (
// action?.type === "GO_BACK" && //
currentRoute?.name === "StreamerSpace" // PageA
) {
getNoticesMaskInformation();
}
});
return unsubscribe;
}, [navigation]);
const renderIndicator = useCallback((props) => {
const { position, navigationState, getTabWidth } = props;
const inputRange = [0, 1];
@ -259,7 +300,7 @@ export default function StreamerSpace({ navigation, route }) {
);
const BecomeIronFanModal = useCallback(
() => (
<Modal
<RNModal
visible={isIronFanModalVisible}
transparent={true}
statusBarTranslucent
@ -330,7 +371,7 @@ export default function StreamerSpace({ navigation, route }) {
</Text>
</TouchableOpacity>
</TouchableOpacity>
</Modal>
</RNModal>
),
[isIronFanModalVisible]
);
@ -608,34 +649,6 @@ export default function StreamerSpace({ navigation, route }) {
查看微信
</Text>
</TouchableOpacity>
{data?.is_superfanship_enabled === 1 && (
<TouchableOpacity
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
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")}
>
<NativeImage
source={require("../../assets/icon/others/chaofen.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
{data?.is_superfanship_unlocked === 1
? "尊贵超粉"
: "成为超粉"}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() => setIsIronFanModalVisible(true)}
style={tailwind("flex flex-col items-center")}
@ -664,6 +677,34 @@ export default function StreamerSpace({ navigation, route }) {
</Text>
</View>
</TouchableOpacity>
{data?.is_superfanship_enabled === 1 && (
<TouchableOpacity
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
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")}
>
<NativeImage
source={require("../../assets/icon/others/chaofen.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
{data?.is_superfanship_unlocked === 1
? "尊贵超粉"
: "成为超粉"}
</Text>
</TouchableOpacity>
)}
</View>
)}
{/* 点击成为铁粉Modal */}
@ -688,7 +729,7 @@ export default function StreamerSpace({ navigation, route }) {
/>
)}
{/* 退款中禁止查看Modal */}
<MyModal
<RNModal
visible={isRefundingModalVisible}
setVisible={setIsRefundingModalVisible}
title="当前空间正在退款中"
@ -729,6 +770,142 @@ export default function StreamerSpace({ navigation, route }) {
</Svg>
</Animated.View>
</TouchableOpacity>
{/* 信息通知弹窗 */}
{popVisible && (
<Modal
isVisible={popVisible}
swipeDirection={["down"]}
onSwipeComplete={() => setPopVisible(false)}
onBackdropPress={() => setPopVisible(false)}
animationInTiming={500} //
animationOutTiming={1000} //
animationIn="bounceInUp" //
animationOut="bounceInDown" //
style={{
height: 120,
paddingBottom: 0,
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
margin: 0,
justifyContent: "flex-end",
}}
>
<View
style={{
...tailwind("w-full"),
backgroundColor: "#17161A",
paddingBottom: 20,
}}
>
<Image
style={{
height: 160,
width: "100%",
marginTop: -30,
}}
source={require("../../assets/images/newM.png")}
placeholder={blurhash}
contentFit="fill"
transition={1000}
cachePolicy="disk"
/>
{/* <NativeImage
source={require("../../assets/icon/others/newM.png")}
/> */}
<View
style={{
...tailwind(
"w-full flex justify-center items-center flex-col"
),
padding: 14,
// marginTop: -30,
}}
>
<Text
style={{
color: "#FFFFFFB2",
fontSize: 13,
lineHeight: 18,
marginBottom: 28,
textAlign: "center",
}}
>
{noticesMaskInformation.content}
</Text>
<View className="w-full">
{noticesMaskInformation.action?.map((item, index) => {
return (
<View
key={index}
style={{
...tailwind(
"w-full flex-row justify-between items-center"
),
height: 56,
borderRadius: 12,
marginBottom: 10,
padding: 14,
backgroundColor: "#2F2E32",
display: item.count > 0 ? "flex" : "none",
}}
>
<View style={{ ...tailwind("flex-row items-center") }}>
<Image
source={
process.env.EXPO_PUBLIC_WEB_ASSETS_URL +
item?.icon_url
}
style={{ width: 28, height: 28, marginRight: 5 }}
/>
<Text
style={tailwind("text-white text-base font-medium")}
>
{item.text} {item.count}
</Text>
</View>
<TouchableOpacity
onPress={() => {
setPopVisible(false);
const linkAndParams = item.app_url
.split("/")
.filter((item) => item);
navigation.navigate(linkAndParams[0], {
screen: linkAndParams[1],
});
}}
style={tailwind(
"flex-row items-center justify-center h-8 px-4 bg-[#FF669E] rounded-full"
)}
>
<Text
style={tailwind("text-white text-sm font-medium")}
>
前往处理
</Text>
</TouchableOpacity>
</View>
);
})}
</View>
<TouchableOpacity
onPress={() => setPopVisible(false)}
style={{
...tailwind(
"flex items-center justify-center h-8 px-4 bg-[#FF669E] rounded-full"
),
height: 46,
width: 221,
marginTop: 41,
}}
>
<Text style={tailwind("text-white text-sm font-medium")}>
回到空间
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
)}
</BottomSheetModalProvider>
</GestureHandlerRootView>
);

View File

@ -6362,7 +6362,7 @@ prop-types@15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
prop-types@15.8.1, prop-types@^15.5.10, prop-types@^15.7.2, prop-types@^15.7.x:
prop-types@15.8.1, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.7.x:
version "15.8.1"
resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -6482,6 +6482,13 @@ react-is@^17.0.1:
resolved "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-native-animatable@1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a"
integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==
dependencies:
prop-types "^15.7.2"
react-native-communications@2.2.1:
version "2.2.1"
resolved "https://registry.npmmirror.com/react-native-communications/-/react-native-communications-2.2.1.tgz"
@ -6541,6 +6548,14 @@ react-native-lightbox-v2@0.9.0:
resolved "https://registry.npmmirror.com/react-native-lightbox-v2/-/react-native-lightbox-v2-0.9.0.tgz"
integrity sha512-Fc5VFHFj2vokS+OegyTsANKb1CYoUlOtAv+EBH5wtpJn1b5cey6jVXH7136G5+8OC9JmKWSgKHc5thFwOoZTUg==
react-native-modal@^13.0.1:
version "13.0.1"
resolved "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz#691f1e646abb96fa82c1788bf18a16d585da37cd"
integrity sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==
dependencies:
prop-types "^15.6.2"
react-native-animatable "1.3.3"
react-native-pager-view@6.3.0:
version "6.3.0"
resolved "https://registry.npmmirror.com/react-native-pager-view/-/react-native-pager-view-6.3.0.tgz"