tiefen_space_app/screeens/Setting/SwitchAccount/index.jsx

319 lines
9.8 KiB
JavaScript

import {
View,
Text,
FlatList,
Image as NativeImage,
ActivityIndicator,
TouchableOpacity,
} from "react-native";
import React, {
useState,
useEffect,
useRef,
useCallback,
useContext,
} from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { ListItem, Button, Icon } from "@rneui/themed";
import { Image } from "expo-image";
import Empty from "../../../components/Empty";
import { get, remove, save } from "../../../utils/storeInfo";
import { AuthContext } from "../../../App";
import baseRequest from "../../../utils/baseRequest";
import { generateSignature } from "../../../utils/crypto";
import MyModal from "../../../components/MyModal";
import Toast from "react-native-toast-message";
export default function SwitchAccount({ navigation, route }) {
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
//退出登陆
const { signIn, signOut } = useContext(AuthContext);
const [accountList, setAccountList] = useState([]);
useEffect(() => {
//获取所有可切换账号
async function getAccountList() {
try {
const keys = await AsyncStorage.getAllKeys();
const accountKeys = keys.filter((key) =>
key.startsWith(`account_list_`)
);
const accountListCache = await AsyncStorage.multiGet(accountKeys);
const jsonParsedAccountList = accountListCache.map((item) => ({
key: item[0],
data: JSON.parse(item[1]),
}));
//判断当前账号是否登录并将登陆的账号放到第一位
const account = await get("account");
const allAccountList = jsonParsedAccountList
.map((item) => ({
...item,
online: item.data.account.user_id === account.user_id,
}))
.sort((a, b) => {
if (!b.data.login_time && !a.data.login_time) return 0;
if (!a.data.login_time) return 1;
if (!b.data.login_time) return -1;
return b.data.login_time - a.data.login_time;
});
//删除没有设置密码且不在线的账号
const _accountList = allAccountList.filter(
(item) => item.data?.password !== undefined || item.online === true
);
setAccountList(_accountList);
} catch (error) {
console.error(error);
}
}
getAccountList();
}, []);
//接口登录
const signInAccount = async (data) => {
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const base = await baseRequest();
const signature = await generateSignature({
mobile_phone: data.mobile_phone,
region_code: data.region_code,
password: data.password,
...base,
});
try {
const _response = await fetch(
`${apiUrl}/api/login/login_by_pswd?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mobile_phone: data.mobile_phone,
region_code: data.region_code,
password: data.password,
...base,
}),
}
);
const _data = await _response.json();
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
//更新登录时间
await save(`account_list_${data.account.user_id}`, {
...data,
login_time: new Date().getTime(),
});
signIn(_data, data.mobile_phone_origion, data.region_code);
setAccountList((pre) =>
pre.map((item) => ({
...item,
online: item.data.account.user_id === data.account.user_id,
}))
);
} catch (error) {
console.error(error);
}
};
//切换账号
const [isSwitching, setIsSwitching] = useState(false);
const [warnModalVisible, setWarnModalVisible] = useState(false);
const [warnModalData, setWarnModalData] = useState({});
const switchAccount = async (data) => {
const onlineAccount = accountList.filter((item) => item.online === true);
if (onlineAccount[0].data.account.user_id === data.account.user_id) return;
if (!onlineAccount[0].data?.password) {
setWarnModalVisible(true);
setWarnModalData(data);
return;
}
setIsSwitching(true);
await signInAccount(data);
setIsSwitching(false);
};
//从验证码登录的账号进行切换账号
const switchAccountWithPhoneNumLogin = async (data) => {
setIsSwitching(true);
const onlineAccount = accountList.filter((item) => item.online === true);
setAccountList((pre) =>
pre.filter(
(item) =>
item.data.account.user_id !== onlineAccount[0].data.account.user_id
)
);
await signInAccount(data);
setIsSwitching(false);
};
//删除账号
const removeAccount = async (key, online) => {
await remove(key);
if (online) {
signOut();
return;
}
setAccountList((pre) => pre.filter((item) => item.key !== key));
};
//账号卡片组件
const AccountCard = useCallback(
({ data, listRef }) => {
return (
<ListItem.Swipeable
onPress={() => switchAccount(data.data)}
bottomDivider
onSwipeBegin={() => {
listRef.current.setNativeProps({
scrollEnabled: false,
});
}}
onSwipeEnd={() => {
listRef.current.setNativeProps({
scrollEnabled: true,
});
}}
containerStyle={tailwind("p-0 bg-[#07050A]")}
rightContent={(reset) => (
<Button
title="删除"
onPress={() => {
removeAccount(data.key, data.online);
reset();
}}
icon={{ name: "delete", color: "white" }}
buttonStyle={{ minHeight: "100%", backgroundColor: "red" }}
titleStyle={tailwind("text-base")}
/>
)}
>
<View style={tailwind("flex-1")}>
<View style={tailwind("flex-row py-3")}>
<Image
style={tailwind("w-12 h-12 rounded-full")}
source={data.data.account.avatar.images[0].urls[0]}
placeholder={blurhash}
contentFit="cover"
transition={1000}
cachePolicy="disk"
/>
<View
style={tailwind(
"flex flex-col flex-1 ml-2 justify-around items-start"
)}
>
<Text
style={tailwind("text-base text-white font-medium")}
numberOfLines={1}
ellipsizeMode="tail"
>
{data.data.account.name}
</Text>
<View
style={tailwind(
"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")}
>
{data.data.account.user_id}
</Text>
</View>
</View>
{data.online && (
<View style={tailwind("flex justify-center")}>
<Icon
type="ionicon"
name="checkmark"
size={24}
color="#27F5B7"
/>
</View>
)}
</View>
</View>
</ListItem.Swipeable>
);
},
[accountList]
);
//删除账号的时候禁用FlatList的滑动
const accountListRef = useRef(null);
//单个账号卡片
const renderItem = ({ item }) => (
<AccountCard data={item} listRef={accountListRef} />
);
return (
<View
style={{
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
<View style={tailwind("px-4 flex-1")}>
<FlatList
ref={accountListRef}
data={accountList}
renderItem={renderItem}
initialNumToRender={6}
ListEmptyComponent={<Empty type="nodata" />}
ListFooterComponent={
<TouchableOpacity
onPress={signOut}
style={tailwind(
"flex flex-row items-center justify-center py-2 bg-[#FFFFFF1A] rounded-full mt-4"
)}
>
<Icon type="ionicon" name="add-outline" size={24} color="white" />
<Text style={tailwind("text-white text-base font-medium ml-1")}>
添加或注册账号
</Text>
</TouchableOpacity>
}
/>
</View>
{isSwitching && (
<View
style={tailwind(
"absolute flex w-full h-full items-center justify-center"
)}
>
<ActivityIndicator size="large" />
</View>
)}
<MyModal
visible={warnModalVisible}
setVisible={setWarnModalVisible}
title="是否继续切换?"
content="当前账号为验证码登录,切换账号会导致当前登录状态失效,无法快速切换回此账号,需进行一次密码登录方可保存快速切换账号。"
cancel={() => {
setWarnModalVisible(false);
}}
confirm={() => {
setWarnModalVisible(false);
switchAccountWithPhoneNumLogin(warnModalData);
}}
/>
</View>
);
}