tiefen_space_app/screeens/Search/index.jsx

1134 lines
36 KiB
JavaScript

import {
View,
Text,
Image as NativeImage,
ScrollView,
TouchableOpacity,
Dimensions,
} from "react-native";
import React, { useState, useEffect, useRef } from "react";
import { useTailwind } from "tailwind-rn";
import {
useSafeAreaInsets,
SafeAreaProvider,
} from "react-native-safe-area-context";
import {
SearchBar,
ListItem,
Icon,
CheckBox,
BottomSheet,
} from "@rneui/themed";
import { Image } from "expo-image";
import Empty from "../../components/Empty";
import Toast from "react-native-toast-message";
import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
import MyDivider from "../../components/MyDivider/index";
import MySlider from "../../components/MySlider";
import Picker from "../../components/Picker";
import { get } from "../../utils/storeInfo";
export default function Search({ navigation, route }) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const searchRef = useRef(null);
const screenDimensions = Dimensions.get("screen");
const [search, setSearch] = useState("");
const [isMember, setIsMember] = useState(0);
const [streamers, setStreamers] = useState([]);
const [recommList, setRecommList] = useState([]);
const [zones, setZones] = useState([]);
const [isloading, setIsloading] = useState(false);
const [isFilterVisible, setIsFilterVisible] = useState({
comprehensive: false,
zone_admission_price: false,
});
const filters = [
{
name: "年龄",
upper_bound: 60,
lower_bound: 18,
default: 19,
step: 1,
type: "slider",
unit: "岁",
key: "age",
stepValues: Array(61)
.fill(null)
.map((_, index) => index),
},
{
name: "全网粉丝",
upper_bound: 200,
lower_bound: 1,
default: 24,
step: 200 / 10,
type: "slider",
unit: "万",
key: "fans",
stepValues: [1, 3, 5, 10, 20, 50, 75, 100, 150, 200, 1000],
},
{
name: "身高",
upper_bound: 200,
lower_bound: 140,
default: 160,
step: 1,
type: "slider",
unit: "CM",
key: "height",
stepValues: Array(201)
.fill(null)
.map((_, index) => index),
},
{
name: "体重",
upper_bound: 100,
lower_bound: 35,
default: 50,
step: 1,
type: "slider",
unit: "KG",
key: "weight",
stepValues: Array(101)
.fill(null)
.map((_, index) => index),
},
{
name: "所在地",
upper_bound: 1000,
lower_bound: 10,
default: 24,
step: 1,
type: "select",
items: [
"北京市",
"天津市",
"河北省",
"山西省",
"内蒙古自治区",
"辽宁省",
"吉林省",
"黑龙江省",
"上海市",
"江苏省",
"浙江省",
"安徽省",
"福建省",
"江西省",
"山东省",
"河南省",
"湖北省",
"湖南省",
"广东省",
"广西壮族自治区",
"海南省",
"重庆市",
"四川省",
"贵州省",
"云南省",
"西藏自治区",
"陕西省",
"甘肃省",
"青海省",
"宁夏回族自治区",
"新疆维吾尔自治区",
"台湾省",
"香港特别行政区",
"澳门特别行政区",
],
key: "city",
},
{
name: "星座",
upper_bound: 1000,
lower_bound: 10,
default: 24,
step: 1,
type: "select",
key: "constellation",
items: [
"白羊座",
"‌金牛座",
"‌双子座",
"‌巨蟹座",
"‌狮子座",
"‌处女座",
"‌天秤座",
"‌天蝎座",
"‌射手座",
"‌摩羯座",
"‌水瓶座",
"‌双鱼座",
],
},
{
name: "最近7日内空间有更新",
upper_bound: 1000,
lower_bound: 10,
default: 24,
step: 1,
type: "checkbox",
key: "is_active_within_a_week",
},
];
const priceFilters = [
{
name: "空间价格",
upper_bound: 200,
lower_bound: 0,
default: 24,
step: 200 / 7,
type: "slider",
unit: "¥",
key: "zone",
stepValues: [0, 1, 10, 50, 100, 150, 200, 4000],
},
{
name: "微信价格",
upper_bound: 200,
lower_bound: 0,
default: 24,
step: 200 / 8,
type: "slider",
unit: "金币",
key: "wechat",
stepValues: [0, 10, 100, 200, 500, 1000, 5000, 10000, 100000],
},
];
const [filtersValue, setFiltersValue] = useState({
age: { lower_bound: 18, upper_bound: 60 },
fans: { lower_bound: 1, upper_bound: 1000 },
height: { lower_bound: 140, upper_bound: 200 },
weight: { lower_bound: 35, upper_bound: 100 },
city: "",
constellation: "",
is_active_within_a_week: 0,
zone_admission_price: { lower_bound: 0, upper_bound: 4000 },
wechat_coin_price: { lower_bound: 0, upper_bound: 100000 },
priceUsed: { show: false, used: false },
comprehensiveUsed: { show: false, used: false },
});
const updateSearch = (search) => {
setSearch(search);
if (!search) return;
setIsloading(true);
};
//进入页面默认focus
useEffect(() => {
searchRef.current.focus();
getIsMember();
}, []);
//搜索框文本变化时进行搜索
useEffect(() => {
if (!search) {
setStreamers([]);
setZones([]);
return;
}
const isNumeric = (str) => {
return /^\d+$/.test(str);
};
const getResult = async () => {
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const isSearchInt = isNumeric(search);
let api;
let querryParams;
if (isSearchInt) {
api = "/api/streamer/list_ext_fuzzily_by_user_id";
querryParams = { user_id: parseInt(search, 10) };
} else {
api = "/api/streamer/list_ext_fuzzily_by_name";
querryParams = { name: search };
}
try {
const base = await baseRequest();
const signature = await generateSignature({
...base,
...querryParams,
offset: 0,
limit: 20,
});
const response = await fetch(`${apiUrl}${api}?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
...querryParams,
offset: 0,
limit: 20,
}),
});
const data = await response.json();
if (data.ret === -1) {
Toast.show({
type: "error",
text1: data.msg,
topOffset: 60,
});
return;
}
if (!ignore) {
const zonesData = data.data.list.filter(
(item) => item.zones.length > 0
);
setStreamers(data.data.list);
setZones(zonesData);
}
setIsloading(false);
} catch (error) {
console.error(error);
}
};
let ignore = false;
getResult();
return () => {
ignore = true;
};
}, [search]);
const getFiltersResult = async () => {
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
let api;
let querryParams;
api = "/api/streamer/filter";
let currentFilterValue = { ...filtersValue };
delete currentFilterValue.comprehensiveUsed;
delete currentFilterValue.priceUsed;
querryParams = currentFilterValue;
try {
const base = await baseRequest();
const signature = await generateSignature({
...base,
...querryParams,
offset: 0,
limit: 20,
});
const response = await fetch(`${apiUrl}${api}?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
...querryParams,
offset: 0,
limit: 20,
}),
});
const data = await response.json();
if (data.ret === -1) {
Toast.show({
type: "error",
text1: data.msg,
topOffset: 60,
});
return;
}
const zonesData = data.data.streamer_list.filter(
(item) => item.zones.length > 0
);
setStreamers(data.data.streamer_list);
setZones(zonesData);
setRecommList(data.data.recomm_list);
setIsloading(false);
} catch (error) {
console.error(error);
}
};
const getIsMember = async () => {
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
let api;
api = "/api/account/list_by_mid";
const account = await get("account");
try {
const base = await baseRequest();
const signature = await generateSignature({
...base,
mid: account.mid,
});
const response = await fetch(`${apiUrl}${api}?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
mid: account.mid,
}),
});
const data = await response.json();
setIsMember(data.data.account.is_a_member);
} catch (error) {
console.error(error);
}
};
//重置筛选值
const handleResetFiltersValue = (type) => {
let obj = {};
if (type == "comprehensive") {
obj = {
...filtersValue,
age: { lower_bound: 18, upper_bound: 60 },
fans: { lower_bound: 1, upper_bound: 1000 },
weight: { lower_bound: 35, upper_bound: 100 },
height: { lower_bound: 140, upper_bound: 200 },
city: "",
constellation: "",
is_active_within_a_week: 0,
comprehensiveUsed: { show: false, used: false },
};
} else {
obj = {
...filtersValue,
zone_admission_price: { lower_bound: 0, upper_bound: 4000 },
wechat_coin_price: { lower_bound: 0, upper_bound: 100000 },
priceUsed: { show: false, used: false },
};
}
setFiltersValue((old) => ({
...old,
...obj,
}));
if (!obj.comprehensiveUsed.used && !obj.priceUsed.used) {
setRecommList([]);
setStreamers([]);
setZones([]);
}
};
//空间组件
const ZoneItem = ({ item }) => {
return (
<ListItem
onPress={() =>
navigation.navigate("SpaceIntroduce", { mid: item?.mid })
}
containerStyle={tailwind("p-0 bg-[#07050A]")}
>
<View style={tailwind("flex flex-col flex-1")}>
<View style={tailwind("flex-row py-3")}>
<Image
style={tailwind("w-12 h-12 rounded-full")}
source={item?.avatar?.images[0]?.urls[0]}
contentFit="cover"
cachePolicy="disk"
/>
<View style={tailwind("ml-2 justify-around flex-1")}>
<View style={tailwind("flex flex-row items-center")}>
<Text
style={tailwind("text-base text-white font-medium")}
numberOfLines={1}
ellipsizeMode="tail"
>
{item?.name}
</Text>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 ml-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/ID.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{item?.user_id}
</Text>
</View>
</View>
<Text
style={tailwind("text-sm text-[#FFFFFF80]")}
numberOfLines={1}
ellipsizeMode="tail"
>
{item.zones[0].profile}
</Text>
</View>
</View>
{zones.length === 1 && (
<View
style={tailwind("flex flex-col bg-[#FFFFFF1A] rounded-xl mb-2")}
>
<Text
style={tailwind(
"text-[#FFFFFF80] text-sm font-medium mt-2 ml-2"
)}
>
Ta的动态·
{item.zones[0].zone_moment_count > 99
? "99+"
: item.zones[0].zone_moment_count}
{item.zones[0].image_count > 0 &&
` | 图片·${
item.zones[0].image_count > 99
? "99+"
: item.zones[0].image_count
}`}
{item.zones[0].video_count > 0 &&
` | 视频·${
item.zones[0].video_count > 99
? "99+"
: item.zones[0].video_count
}`}
</Text>
<View
style={{
aspectRatio: "1/1",
...tailwind("flex flex-row"),
}}
>
<View
style={{
flexBasis: "66.66%",
paddingTop: 8,
paddingRight: 8,
}}
>
<Image
style={tailwind("rounded-xl w-full h-full")}
source={item?.shorts?.videos[0]?.cover_urls[0]}
contentFit="cover"
cachePolicy="disk"
/>
<View
style={tailwind(
"flex absolute w-full h-full left-0 top-0 z-10 justify-center items-center"
)}
>
<NativeImage
source={require("../../assets/icon/others/play.png")}
/>
</View>
</View>
<View style={tailwind("flex flex-col basis-1/3")}>
<View
style={{
aspectRatio: "1/1",
paddingRight: 0,
paddingTop: 8,
}}
>
<Image
style={tailwind("rounded-xl w-full h-full")}
source={item?.cover?.images[0]?.urls[0]}
contentFit="cover"
cachePolicy="disk"
/>
</View>
{item.album.images.map((_item, index) => {
if (index > 1) return;
return (
<View
key={index}
style={{
aspectRatio: "1/1",
paddingRight: 0,
paddingTop: 8,
}}
>
<Image
style={tailwind("rounded-xl w-full h-full")}
source={_item?.urls[0]}
contentFit="cover"
cachePolicy="disk"
/>
</View>
);
})}
</View>
</View>
</View>
)}
</View>
</ListItem>
);
};
//主播组件
const StreamerItem = ({ item }) => {
return (
<ListItem
onPress={() =>
navigation.navigate("StreamerProfile", {
mid: item.mid,
})
}
containerStyle={tailwind("p-0 bg-[#07050A]")}
>
<View style={tailwind("flex-1")}>
<View style={tailwind("flex-row py-3")}>
<Image
style={tailwind("w-12 h-12 rounded-full")}
source={item?.avatar?.images[0]?.urls[0]}
contentFit="cover"
transition={1000}
cachePolicy="disk"
/>
<View style={tailwind("ml-2 justify-around flex-1")}>
<View style={tailwind("flex flex-row items-center")}>
<Text
style={tailwind("text-base text-white font-medium")}
numberOfLines={1}
ellipsizeMode="tail"
>
{item?.name}
</Text>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 ml-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/ID.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{item?.user_id}
</Text>
</View>
</View>
<Text
style={tailwind("text-sm text-[#FFFFFF80]")}
numberOfLines={1}
ellipsizeMode="tail"
>
{item.bio}
</Text>
</View>
</View>
</View>
</ListItem>
);
};
return (
<View
style={{
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
<View style={tailwind("flex-row px-2 items-center")}>
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
<SearchBar
ref={searchRef}
containerStyle={tailwind("flex-1 bg-[#07050A]")}
inputContainerStyle={tailwind("h-10 bg-[#FFFFFF1A]")}
inputStyle={tailwind("text-white")}
placeholder="搜索Ta的昵称或id"
platform="ios"
cancelButtonProps={tailwind("text-[#FF669E]")}
cancelButtonTitle="清空"
clearIcon={() => <></>}
searchIcon={() => <></>}
showLoading={isloading}
onChangeText={updateSearch}
value={search}
disabled={
filtersValue.comprehensiveUsed.used || filtersValue.priceUsed.used
}
/>
</View>
<ScrollView style={tailwind("flex-1")}>
<View style={tailwind("flex flex-row justify-around")}>
<TouchableOpacity
onPress={() => {
setIsFilterVisible({
...isFilterVisible,
comprehensive: !isFilterVisible.comprehensive,
});
}}
style={{
...tailwind("px-2 rounded-xl flex-row items-center"),
borderColor: "#ff75c8",
borderWidth: filtersValue.comprehensiveUsed.used ? 1 : 0,
boxSizing: "border-box",
width: 110,
}}
>
<Text
style={{
...tailwind("text-white text-lg font-medium"),
marginVertical: 6,
color: filtersValue.comprehensiveUsed.used
? "#ff75c8"
: "#ffffff80",
}}
>
综合筛选
</Text>
{filtersValue.comprehensiveUsed.used && (
<TouchableOpacity
onPress={() => handleResetFiltersValue("comprehensive")}
style={{ width: 24 }}
>
<Icon
type="ionicon"
name="close"
size={18}
color="#ff75c8"
style={{ marginLeft: 2 }}
/>
</TouchableOpacity>
)}
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
setIsFilterVisible({
...isFilterVisible,
zone_admission_price: !isFilterVisible.zone_admission_price,
});
}}
style={{
...tailwind("px-2 rounded-xl flex-row items-center"),
borderColor: "#ff75c8",
borderWidth: filtersValue.priceUsed.used ? 1 : 0,
boxSizing: "border-box",
width: 110,
}}
>
<Text
style={{
...tailwind("text-white text-lg font-medium"),
marginVertical: 6,
color: filtersValue.priceUsed.used ? "#ff75c8" : "#ffffff80",
}}
>
价格筛选
</Text>
{filtersValue.priceUsed.used && (
<TouchableOpacity
onPress={() => handleResetFiltersValue("zone_admission_price")}
style={{ width: 24 }}
>
<Icon
type="ionicon"
name="close"
size={18}
color="#ff75c8"
style={{ marginLeft: 2 }}
/>
</TouchableOpacity>
)}
</TouchableOpacity>
</View>
<View
style={{
display: "flex",
flex: 1,
}}
>
<BottomSheet
// containerStyle={{ marginTop: 80 }}
backdropStyle={{ backgroundColor: "#0000004d" }}
scrollViewProps={{
contentContainerStyle: {
// paddingTop: 20,
backgroundColor: "black",
borderRadius: 12,
},
onScroll: (event) => {
const { y } = event.nativeEvent.contentOffset;
if (y < -50) {
setIsFilterVisible({
zone_admission_price: false,
comprehensive: false,
});
}
},
}}
isVisible={isFilterVisible.comprehensive}
style={{
paddingTop: 110,
}}
>
<View>
{filters.map((item, index) => (
<View
style={{
...tailwind(`p-4 rounded-xl`),
backgroundColor: "#13121f",
margin: 18,
marginBottom: 6,
flexDirection: item.type !== "slider" ? "row" : "col",
justifyContent: "space-between",
// alignItems: "center",
// paddingBottom: 50,
}}
>
<Text
style={{
...tailwind("text-white font-medium"),
marginVertical: 6,
}}
>
{item.name}
</Text>
{item.type == "slider" ? (
<MySlider
height={40}
lower_bound={item.lower_bound}
upper_bound={item.upper_bound}
itemKey={item.key}
leftValue={
item.key == "age"
? filtersValue.age.lower_bound
: item.key == "height"
? filtersValue.height.lower_bound
: item.key == "weight"
? filtersValue.weight.lower_bound
: filtersValue.fans.lower_bound
}
rightValue={
item.key == "age"
? filtersValue.age.upper_bound
: item.key == "height"
? filtersValue.height.upper_bound
: item.key == "weight"
? filtersValue.weight.upper_bound
: filtersValue.fans.upper_bound
}
step={item.step}
hasInfinity={item.key == "fans"}
stepValues={item.stepValues}
onChange={(value) => {
if (item.key == "age") {
setFiltersValue((old) => ({ ...old, age: value }));
} else if (item.key == "fans") {
setFiltersValue((old) => ({ ...old, fans: value }));
} else if (item.key == "height") {
setFiltersValue((old) => ({ ...old, height: value }));
} else if (item.key == "weight") {
setFiltersValue((old) => ({ ...old, weight: value }));
}
}}
maximumTrackTintColor="#ff75c81a"
minimumTrackTintColor="#ff75c8"
processHeight={5}
unit={item.unit}
thumbImage={require("../../assets/icon/32DP/edit.png")}
/>
) : item.type == "checkbox" ? (
<CheckBox
checked={filtersValue.is_active_within_a_week}
onPress={() =>
setFiltersValue((old) => ({
...old,
is_active_within_a_week: old.is_active_within_a_week
? 0
: 1,
}))
}
iconType="material-community"
checkedIcon="checkbox-marked"
uncheckedIcon="checkbox-blank-outline"
checkedColor="#FF669E"
containerStyle={tailwind("p-0 m-0 bg-transparent")}
size={24}
/>
) : (
<Picker
items={item.items?.map((it, index) => ({
label: it,
value: it,
}))}
value={
item.key == "constellation"
? filtersValue.constellation
: filtersValue.city
}
onChange={(value) =>
setFiltersValue((old) => {
let newValue = { ...old };
if (item.key == "constellation") {
newValue.constellation = value;
} else {
newValue.city = value;
}
return newValue;
})
}
/>
)}
</View>
))}
<View
style={{
...tailwind("flex-row justify-around mb-4"),
}}
>
{isMember == 1 && (
<TouchableOpacity
style={{
...tailwind("text-white px-4 py-2 rounded-xl"),
marginVertical: 6,
backgroundColor: "#ffffff1a",
width: 120,
}}
onPress={() => handleResetFiltersValue("comprehensive")}
>
<Text
style={{
...tailwind(
"text-white text-lg font-medium text-center"
),
}}
>
重置
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() => {
setIsFilterVisible({
zone_admission_price: false,
comprehensive: false,
});
if (!isMember) {
navigation.navigate("WebWithoutHeader", {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
});
return;
}
setFiltersValue((old) => ({
...old,
comprehensiveUsed: { show: false, used: true },
}));
getFiltersResult();
}}
style={{
...tailwind("text-white px-4 py-2 rounded-xl"),
marginVertical: 6,
backgroundColor: "#ff75c8",
minWidth: 120,
}}
>
<Text
style={{
...tailwind(
"text-white text-lg font-medium text-center"
),
}}
>
{!isMember ? "开通VIP后即可筛选" : "确定"}
</Text>
</TouchableOpacity>
</View>
</View>
</BottomSheet>
<BottomSheet
backdropStyle={{ backgroundColor: "#0000004d" }}
scrollViewProps={{
contentContainerStyle: {
// paddingTop: 20,
backgroundColor: "black",
borderRadius: 12,
},
onScroll: (event) => {
const { y } = event.nativeEvent.contentOffset;
if (y < -50) {
setIsFilterVisible({
zone_admission_price: false,
comprehensive: false,
});
}
},
}}
isVisible={isFilterVisible.zone_admission_price}
style={{
paddingTop: 110,
}}
>
<View
style={{
backgroundColor: "black",
borderRadius: 12,
// flex: 1,
// position: "relative",
height: screenDimensions.height - 120,
}}
>
{priceFilters.map((item) => (
<View
style={{
...tailwind(`p-4 rounded-xl`),
backgroundColor: "#13121f",
margin: 18,
marginBottom: 6,
flexDirection: item.type !== "slider" ? "row" : "col",
justifyContent: "space-between",
// alignItems: "center",
// paddingBottom: 50,
}}
>
<Text
style={{
...tailwind("text-white font-medium"),
marginVertical: 6,
}}
>
{item.name}
</Text>
<MySlider
height={40}
lower_bound={item.lower_bound}
upper_bound={item.upper_bound}
leftValue={
item.key == "zone"
? filtersValue.zone_admission_price.lower_bound
: filtersValue.wechat_coin_price.lower_bound
}
rightValue={
item.key == "zone"
? filtersValue.zone_admission_price.upper_bound
: filtersValue.wechat_coin_price.upper_bound
}
stepValues={item.stepValues}
step={item.step}
hasInfinity={true}
itemKey={item.key}
onChange={(value) => {
if (item.key == "zone") {
setFiltersValue((old) => ({
...old,
zone_admission_price: value,
}));
} else if (item.key == "wechat") {
setFiltersValue((old) => ({
...old,
wechat_coin_price: value,
}));
}
}}
maximumTrackTintColor="#ff75c81a"
minimumTrackTintColor="#ff75c8"
processHeight={5}
unit={item.unit}
thumbImage={require("../../assets/icon/32DP/edit.png")}
/>
</View>
))}
<View
style={{
...tailwind("flex-row justify-around mb-4"),
position: "absolute",
bottom: 0,
width: "100%",
}}
>
{isMember == 1 && (
<TouchableOpacity
style={{
...tailwind("text-white px-4 py-2 rounded-xl"),
marginVertical: 6,
backgroundColor: "#ffffff1a",
width: 120,
}}
onPress={() =>
handleResetFiltersValue("zone_admission_price")
}
>
<Text
style={{
...tailwind(
"text-white text-lg font-medium text-center"
),
}}
>
重置
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() => {
setIsFilterVisible({
zone_admission_price: false,
comprehensive: false,
});
if (!isMember) {
navigation.navigate("WebWithoutHeader", {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
});
return;
}
setFiltersValue((old) => ({
...old,
priceUsed: { show: false, used: true },
}));
getFiltersResult();
}}
style={{
...tailwind("text-white px-4 py-2 rounded-xl"),
marginVertical: 6,
backgroundColor: "#ff75c8",
minWidth: 120,
}}
>
<Text
style={{
...tailwind(
"text-white text-lg font-medium text-center"
),
}}
>
{!isMember ? "开通VIP后即可筛选" : "确定"}
</Text>
</TouchableOpacity>
</View>
</View>
</BottomSheet>
</View>
<View style={tailwind("flex-1 px-4")}>
{zones.length > 0 && (
<Text style={tailwind("mt-2 text-white text-xl font-medium")}>
空间
</Text>
)}
{zones?.map((item, index) => (
<ZoneItem key={index} item={item} />
))}
{zones.length > 0 && <MyDivider style={tailwind("my-2")} />}
{streamers.length > 0 && (
<Text style={tailwind("mt-2 text-white text-xl font-medium")}>
用户
</Text>
)}
{streamers?.map((item, index) => (
<StreamerItem key={index} item={item} />
))}
{recommList.length > 0 && <MyDivider style={tailwind("my-2")} />}
{recommList.length > 0 && (
<Text style={tailwind("mt-2 text-white text-xl font-medium")}>
猜你喜欢
</Text>
)}
{recommList?.map((item, index) => (
<StreamerItem key={index} item={item} />
))}
{streamers.length === 0 && recommList.length === 0 && (
<Empty type={search ? "search" : "nodata"} />
)}
</View>
</ScrollView>
</View>
);
}