tiefen_space_app/screeens/SpaceSetting/CollaboratorSetting/index.jsx

583 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
View,
Text,
ScrollView,
Modal,
TextInput,
KeyboardAvoidingView,
TouchableOpacity,
Image as NativeImage,
ActivityIndicator,
} from "react-native";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
import { Image } from "expo-image";
import { Icon, Button, ListItem } from "@rneui/themed";
import baseRequest from "../../../utils/baseRequest";
import { generateSignature } from "../../../utils/crypto";
import Picker from "../../../components/Picker";
import MyDivider from "../../../components/MyDivider";
export default function CollaboratorSetting({ navigation, route }) {
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
//获取环境变量
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
//获取数据
const [data, setData] = useState();
const [selfMid, setSelfMid] = useState();
const [isFetching, setIsFetching] = useState(true);
const getData = async () => {
setIsFetching(true);
try {
const base = await baseRequest();
setSelfMid(base.b_mid);
const body = {
zid: route.params.data.id,
visitor_role: route.params.data.visitor_role,
...base,
};
const signature = await generateSignature(body);
const _response = await fetch(
`${apiUrl}/api/zone_collaborator/list?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const _data = await _response.json();
console.log(_data);
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
setData(_data.data);
} catch (error) {
console.error(error);
} finally {
setIsFetching(false);
}
};
useEffect(() => {
getData();
}, []);
//添加协作者Modal
const [idAddCollaboratorModalVisible, setIsAddCollaboratorModalVisible] =
useState(false);
//搜索用户ID以及是否选中用户
const [userId, setUserId] = useState();
const [collaboratorData, setCollaboratorData] = useState();
const [isSelected, setIsSelected] = useState(false);
const handleSearch = async () => {
if (!userId) {
Toast.show({
type: "error",
text1: "请先输入ID",
topOffset: 60,
});
return;
}
const base = await baseRequest();
const signature = await generateSignature({
...base,
user_id: parseInt(userId, 10),
});
try {
//获取账号基本信息
const _response = await fetch(
`${apiUrl}/api/account/list_others_by_user_id?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
user_id: parseInt(userId, 10),
}),
}
);
const _data = await _response.json();
console.log(_data);
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
setCollaboratorData(_data.data.account);
setIsSelected(false);
} catch (error) {
console.error(error);
}
};
//分成比例
const [rate, setRate] = useState();
//计算代运营剩余比例
const remainingRate = useMemo(() => {
if (!data) return;
const totalRate = data?.list?.reduce(
(acc, cur) => acc + cur.sharing_ratio,
0
);
return (data?.zone_third_partner?.sharing_ratio - totalRate).toFixed(2);
}, [data]);
//生成比例选项
const generateItems = useCallback((min, max) => {
const items = [];
for (let i = min; i <= max; i++) {
items.push({ label: `${i.toString()}%`, value: i.toString() });
}
return items;
}, []);
const rates = useMemo(
() => generateItems(1, parseInt(remainingRate * 100)),
[remainingRate]
);
//提交
const handleSubmit = async () => {
if (route.params.data.visitor_role !== 1) return;
if (!isSelected) {
Toast.show({
type: "error",
text1: "请先选中用户",
topOffset: 60,
});
return;
}
if (!rate) {
Toast.show({
type: "error",
text1: "请选择分成比例",
topOffset: 60,
});
return;
}
try {
const base = await baseRequest();
const body = {
zid: route.params.data.id,
collaborator_mid: collaboratorData.mid,
sharing_ratio: parseInt(rate, 10) / 100,
...base,
};
const signature = await generateSignature(body);
const _response = await fetch(
`${apiUrl}/api/zone_collaborator/create?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const _data = await _response.json();
console.log(_data);
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
Toast.show({
type: "success",
text1: "添加合伙人成功",
topOffset: 60,
});
getData();
handleCancel();
} catch (error) {
console.error(error);
}
};
//关闭
const handleCancel = () => {
setIsAddCollaboratorModalVisible(false);
setIsSelected(false);
setCollaboratorData();
setUserId();
setRate();
};
//删除协作者
const handleDelete = async (id) => {
if (route.params.data.visitor_role !== 1) return;
try {
const base = await baseRequest();
const body = {
id: id,
...base,
};
const signature = await generateSignature(body);
const _response = await fetch(
`${apiUrl}/api/zone_collaborator/delete?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const _data = await _response.json();
console.log(_data);
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
Toast.show({
type: "success",
text1: "移除合伙人成功",
topOffset: 60,
});
getData();
handleCancel();
} catch (error) {
console.error(error);
}
};
//单个协作者组件
const CollaboratorItem = useCallback(({ item }) => {
return (
<ListItem bottomDivider containerStyle={tailwind("p-0 bg-transparent")}>
<View style={tailwind("flex-1")}>
<View style={tailwind("flex-row py-3")}>
<Image
style={tailwind("w-12 h-12 rounded-full")}
source={item?.collaborator_account?.avatar?.images[0]?.urls[0]}
placeholder={blurhash}
contentFit="cover"
transition={1000}
cachePolicy="disk"
/>
<View style={tailwind("ml-2 justify-around flex-1")}>
<Text
style={tailwind("text-base text-white font-medium")}
numberOfLines={1}
ellipsizeMode="tail"
>
{item?.collaborator_account?.name}
</Text>
<View style={tailwind("flex-row flex-wrap")}>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 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?.collaborator_account?.user_id}
</Text>
</View>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
)}
>
<Icon
type="ionicon"
name="cash-outline"
size={11}
color="white"
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{item?.sharing_ratio * 100}%
</Text>
</View>
</View>
</View>
{!item?.isDeleteBtnInvisible && (
<View style={tailwind("ml-2 justify-around items-center")}>
<Button
titleStyle={tailwind("text-sm font-medium px-2")}
color={"#F53030"}
radius="999"
size="md"
onPress={() => handleDelete(item.id)}
>
移除
</Button>
</View>
)}
</View>
</View>
</ListItem>
);
}, []);
if (isFetching) {
return (
<View style={tailwind("flex flex-1 justify-center items-center")}>
<ActivityIndicator size="large" />
</View>
);
}
if (route.params.data.visitor_role === 2) {
const selfData = data?.list?.filter(
(item) => item.collaborator_mid === selfMid
);
return (
<View
style={{
gap: 8,
...tailwind(
"flex flex-col border border-2 border-[#2c2b2f] rounded-2xl p-4 w-full mt-6"
),
}}
>
<Text style={tailwind("text-white text-base font-medium")}>
合伙人昵称{selfData.collaborator_account.name}
</Text>
<Text style={tailwind("text-white text-base font-medium")}>
ID{selfData.collaborator_account.user_id}
</Text>
<Text style={tailwind("text-white text-base font-medium")}>
分成比例{data.sharing_ratio * 100}%
</Text>
</View>
);
}
return (
<ScrollView
style={{
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
<View style={tailwind("flex flex-col items-center p-4")}>
<View style={tailwind("flex flex-col items-center")}>
<Text style={tailwind("text-white text-base font-medium")}>
总分成比例
</Text>
<Text style={tailwind("text-[#F53030] text-3xl font-medium my-2")}>
{data?.zone_third_partner?.sharing_ratio * 100}%
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm")}>
修改比例请联系平台客服
</Text>
</View>
<MyDivider style={tailwind("mt-4")} />
<View style={tailwind("flex flex-col w-full")}>
<CollaboratorItem
item={{
collaborator_account:
data?.zone_third_partner?.third_partner_account,
sharing_ratio: remainingRate,
isDeleteBtnInvisible: true,
}}
/>
{data?.list?.map((item, index) => (
<CollaboratorItem key={index} item={item} />
))}
</View>
<Icon
onPress={() => setIsAddCollaboratorModalVisible(true)}
type="ionicon"
name="add"
size={40}
color="white"
containerStyle={tailwind(
"border border-white rounded-full w-[4.6rem] h-[4.6rem] flex items-center justify-center mt-4"
)}
/>
<View style={tailwind("mt-8")}>
<Text style={tailwind("text-[#FFFFFF80] text-base font-medium")}>
注意事项
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm")}>
1总分成比例由当前空间主人设置您的个人分成比例由代运营进行设置
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm")}>
2您的个人收益计算公式为空间收益x个人分成比例=个人收益收益将以钻石形式发放至您的钱包
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm")}>
3若您对收益情况存在任何疑问请联系人工客服
</Text>
</View>
</View>
<Modal
visible={idAddCollaboratorModalVisible}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<TouchableOpacity
activeOpacity={1}
onPress={handleCancel}
style={tailwind("flex flex-1 bg-[#00000080] px-4")}
>
<KeyboardAvoidingView
style={tailwind("flex flex-1 items-center justify-center")}
behavior="padding"
>
<TouchableOpacity
activeOpacity={1}
style={{
gap: 12,
...tailwind(
"flex flex-col w-full bg-[#17171A] rounded-3xl px-4 py-6"
),
}}
>
<View style={tailwind("flex flex-row items-center")}>
<Text style={tailwind("text-white text-base font-medium")}>
搜索用户
</Text>
<TextInput
placeholder="请输入用户ID"
placeholderTextColor="#FFFFFF80"
keyboardType="numeric"
underlineColorAndroid="transparent"
onChangeText={(value) => setUserId(value)}
value={userId}
style={tailwind(
"flex-1 bg-[#FFFFFF1A] text-white rounded-2xl px-4 h-8 mx-2"
)}
/>
<Text
onPress={handleSearch}
style={tailwind("text-[#FF669E] text-base font-medium")}
>
搜索
</Text>
</View>
{collaboratorData && (
<View
style={[
tailwind("flex flex-row items-center rounded-2xl p-4"),
isSelected
? { borderColor: "#FF669E", ...tailwind("border") }
: { borderColor: "#2c2b2f", ...tailwind("border") },
]}
>
<Image
source={collaboratorData?.avatar?.images[0]?.urls[0]}
contentFit="cover"
transition={1000}
placeholder={blurhash}
cachePolicy="disk"
style={tailwind("w-12 h-12 rounded-full")}
/>
<View
style={tailwind(
"flex flex-1 flex-col justify-around items-start ml-2"
)}
>
<Text
style={tailwind("text-base text-white font-medium")}
numberOfLines={1}
ellipsizeMode="tail"
>
{collaboratorData?.name}
</Text>
<View
style={tailwind(
"flex flex-row items-center py-0.5 px-2 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../../assets/icon/12DP/ID.png")}
/>
<Text
style={tailwind(
"text-white text-xs font-medium ml-0.5"
)}
>
{collaboratorData?.user_id}
</Text>
</View>
</View>
<Button
color={isSelected ? "#FFFFFF1A" : "#FF669E"}
radius="999"
size="md"
onPress={() => setIsSelected(!isSelected)}
titleStyle={tailwind("text-base")}
containerStyle={{ width: 80 }}
>
{isSelected ? "取消" : "选择"}
</Button>
</View>
)}
<View style={tailwind("flex flex-row items-center")}>
<Text style={tailwind("text-white text-base font-medium")}>
分成比例
</Text>
<View style={tailwind("w-1/3")}>
<Picker items={rates} onChange={(value) => setRate(value)} />
</View>
</View>
<Text style={tailwind("text-[#F53030] text-xs font-medium")}>
注意事项分成比例不得超过50%且确认后无法修改
</Text>
<View style={tailwind("flex flex-row mt-2")}>
<Button
color="#FF669E"
radius="999"
size="md"
titleStyle={tailwind("text-sm mx-2")}
containerStyle={tailwind("flex-1 px-2")}
onPress={handleSubmit}
>
确认
</Button>
<Button
color="#FFFFFF1A"
radius="999"
size="md"
titleStyle={tailwind("text-sm mx-2")}
containerStyle={tailwind("flex-1 px-2")}
onPress={handleCancel}
>
取消
</Button>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</TouchableOpacity>
<Toast />
</Modal>
</ScrollView>
);
}