import { Ionicons } from "@expo/vector-icons"; import { BottomSheetBackdrop, type BottomSheetBackdropProps, BottomSheetModal, BottomSheetView, } from "@gorhom/bottom-sheet"; import type React from "react"; import { useCallback, useEffect, useMemo, useRef } from "react"; import { useTranslation } from "react-i18next"; import { Alert, Platform, TouchableOpacity, View } from "react-native"; import { Swipeable } from "react-native-gesture-handler"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Colors } from "@/constants/Colors"; import { deleteAccountCredential, type SavedServer, type SavedServerAccount, } from "@/utils/secureCredentials"; import { Button } from "./Button"; import { Text } from "./common/Text"; interface AccountsSheetProps { open: boolean; setOpen: (open: boolean) => void; server: SavedServer | null; onAccountSelect: (account: SavedServerAccount) => void; onAddAccount: () => void; onAccountDeleted?: () => void; } export const AccountsSheet: React.FC = ({ open, setOpen, server, onAccountSelect, onAddAccount, onAccountDeleted, }) => { const { t } = useTranslation(); const insets = useSafeAreaInsets(); const bottomSheetModalRef = useRef(null); const isAndroid = Platform.OS === "android"; const snapPoints = useMemo( () => (isAndroid ? ["100%"] : ["50%"]), [isAndroid], ); useEffect(() => { if (open) { bottomSheetModalRef.current?.present(); } else { bottomSheetModalRef.current?.dismiss(); } }, [open]); const handleSheetChanges = useCallback( (index: number) => { if (index === -1) { setOpen(false); } }, [setOpen], ); const renderBackdrop = useCallback( (props: BottomSheetBackdropProps) => ( ), [], ); const handleDeleteAccount = async (account: SavedServerAccount) => { if (!server) return; Alert.alert( t("server.remove_saved_login"), t("server.remove_account_description", { username: account.username }), [ { text: t("common.cancel"), style: "cancel" }, { text: t("common.remove"), style: "destructive", onPress: async () => { await deleteAccountCredential(server.address, account.userId); onAccountDeleted?.(); }, }, ], ); }; const getSecurityIcon = ( securityType: SavedServerAccount["securityType"], ): keyof typeof Ionicons.glyphMap => { switch (securityType) { case "pin": return "keypad"; case "password": return "lock-closed"; default: return "key"; } }; const renderRightActions = (account: SavedServerAccount) => ( handleDeleteAccount(account)} className='bg-red-600 justify-center items-center px-5' > ); if (!server) return null; return ( {/* Header */} {t("server.select_account")} {server.name || server.address} {/* Account List */} {server.accounts.map((account, index) => ( renderRightActions(account)} overshootRight={false} > { setOpen(false); onAccountSelect(account); }} className={`flex-row items-center p-4 bg-neutral-800 ${ index < server.accounts.length - 1 ? "border-b border-neutral-700" : "" }`} > {/* Avatar */} {/* Account Info */} {account.username} {account.securityType === "none" ? t("save_account.no_protection") : account.securityType === "pin" ? t("save_account.pin_code") : t("save_account.password")} {/* Security Icon */} ))} {/* Hint */} {t("server.swipe_to_remove")} {/* Add Account Button */} ); };