import {Alert, RefreshControl, ScrollView, StyleSheet, Text, View} from "react-native"; import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from "react"; import {ActivityIndicator, Button, Card, Paragraph, Title, useTheme} from "react-native-paper"; import {CircleCheck, CircleDot, CreditCard, Nfc, Plus, SmartphoneNfcIcon, WifiOff} from "lucide-react-native"; import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder"; import {AimeCard} from "../components/AimeCard"; import {BSON} from "realm"; import RealmContext from "../models/RealmContext"; import {AMServer} from "../models/AMServer"; import {AMCard} from "../models/AMCard"; import ObjectId = BSON.ObjectId; const {useRealm, useQuery, useObject} = RealmContext; export default function ServerCardIn({route, navigation}) { const realm = useRealm(); const theme = useTheme(); // card listing state const query = useQuery(AMCard); const cards = useMemo(() => query.sorted("lastUsed", true), [query]); const [selectedCard, setSelectedCard] = useState(null); const [cardInCompleted, setCardInCompleted] = useState(null); const unselectedCards = useMemo(() => { // protect against selected card being removed switch (selectedCard?.isValid()) { case true: return cards.filter(x => !x._id.equals(selectedCard._id)); // clear out invalid case false: setSelectedCard(null); return cards; default: return cards; } }, [cards, selectedCard]); // server state const [serverRefreshing, setServerRefreshing] = useState(false); const [serverReloadCounter, setServerReloadCounter] = useState(0); const [connectionTestResult, setConnectionTestResult] = useState(null); let {serverId} = route.params; const server = useObject(AMServer, ObjectId.createFromHexString(serverId)); useLayoutEffect(() => { if (!server) { return; } navigation.setOptions({ title: server.serverName, }); }, [navigation, server]); // set selected card (once) useEffect(() => { setSelectedCard(cards.length ? cards[0] : null); }, [realm]); // refresh server info (server change or reload request) useEffect(() => { if (server?.isValid() !== true) { navigation.goBack(); // don't show error on invalid server, just means it was deleted if (!server) { Alert.alert("Server not found", "The server you are looking for does not exist."); } return; } const abortController = new AbortController(); server.getInfo(abortController.signal).then(r => { if (r) { setConnectionTestResult(true); realm.write(() => { server.lastUsed = new Date(); Object.keys(r).forEach(x => server[x] = r[x]); }); } else { setConnectionTestResult(false); } }).catch(() => { setConnectionTestResult(false); }).finally(() => { setServerRefreshing(false); }); setTimeout(() => abortController.abort(), 5000); return () => abortController.abort(); }, [serverId, serverReloadCounter, realm]); // card in callback const performCardIn = useCallback(() => { setCardInCompleted(false); const abortController = new AbortController(); server.submitCard(selectedCard.code, abortController.signal).then(r => { setCardInCompleted(r); realm.write(() => { selectedCard.lastUsed = new Date(); setSelectedCard(selectedCard); }); }).catch(() => { setCardInCompleted(false); }).finally(() => { setTimeout(() => setCardInCompleted(null), 3000); }); setTimeout(() => abortController.abort(), 5000); return () => abortController.abort(); }, [server, selectedCard]); if (connectionTestResult === null) { return ( Connecting to server... ) } // cached vars const disableCardIn = cardInCompleted !== null || !connectionTestResult; return ( { setServerRefreshing(true); setServerReloadCounter(serverReloadCounter + 1); }}/>}> {!connectionTestResult && ( Connection Failed There was an issue connecting to the AMNet server at {server.serverAddress}. Check connections and game status and try again. )} Selected Card {selectedCard ? <> }/> : }/> } {cards.length > 0 && ( Additional Cards {unselectedCards.length ? unselectedCards.map(card => ( } onPress={() => setSelectedCard(card)}/>)) : }/> } )} ) } const styles = StyleSheet.create({ section: { gap: 10 }, emptyPlaceholderView: { marginVertical: 30, gap: 15 }, container: { paddingHorizontal: 16, paddingBottom: 25, gap: 20 } })