Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
6.2 kB · 208 lines
TSX
at mistress
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209import { useAuth } from "#/components/SessionProvider";import { Agent } from "@atproto/api";import { useRouter } from "expo-router";import { useEffect, useState } from "react";import { ActivityIndicator, FlatList, Image, Pressable, Text, View } from "react-native";import { getPendingRecords, removePendingRecord, type PendingRecord } from "#/lib/recordQueue";
type PendingEntry = { record: PendingRecord; did: string; handle: string; displayName: string; avatar?: string;};
export function Queue() { const { requireSession, hasSavedDid, isLoading } = useAuth(); const [records, setRecords] = useState<PendingRecord[]>(() => getPendingRecords()); const [entries, setEntries] = useState<PendingEntry[]>([]); const [agent, setAgent] = useState<Agent | null>(null); const [profilesLoading, setProfilesLoading] = useState(false); const [uploading, setUploading] = useState(false);
const router = useRouter();
useEffect(() => { let isMounted = true;
const checkSession = async () => { try { const a = await requireSession();
if (isMounted) { setAgent(a); } } catch (error) { console.error("Failed to require session:", error);
if (isMounted) { router.replace("/sign-in"); } } };
if (!isLoading) { if (!hasSavedDid) { router.replace("/sign-in"); } else { checkSession(); } }
return () => { isMounted = false; }; }, [hasSavedDid, isLoading, router, requireSession]);
useEffect(() => { if (!agent || records.length === 0) { return; }
let isMounted = true;
const loadProfiles = async () => { setProfilesLoading(true);
try { const results = await Promise.all( records.map(async (record): Promise<PendingEntry | null> => { try { const profile = await agent.getProfile({ actor: record.record.Target, });
return { record, did: profile.data.did, handle: profile.data.handle, displayName: profile.data.displayName || profile.data.handle, avatar: profile.data.avatar, }; } catch (error) { console.error(`Failed to load profile for ${record.record.Target}:`, error);
return null; } }), );
if (isMounted) { setEntries(results.filter((entry): entry is PendingEntry => entry !== null)); } } catch (error) { console.error("Failed to load profiles:", error); } finally { if (isMounted) { setProfilesLoading(false); } } };
loadProfiles();
return () => { isMounted = false; }; }, [agent, records]);
const publish = async () => { if (!agent || uploading || records.length === 0) { return; }
setUploading(true);
for (const record of records) { try { const resp = await agent.com.atproto.repo.putRecord({ repo: agent.assertDid, rkey: record.rkey, collection: "club.touchfluffytail.touchedfluffytail", record: record.record, });
if (!resp.success) { throw new Error("once more i thought this was not possible"); } else { // if we some how hit that error we're fucked removePendingRecord(record.rkey); setRecords((prev) => prev.filter((entry) => entry.rkey !== record.rkey)); setEntries((prev) => prev.filter((entry) => entry.record.rkey !== record.rkey)); } } catch { console.error("AHHHHHHHHHHHHHHHHHHHHHHHH"); } }
setUploading(false); };
return ( <View className="flex-1 w-full bg-emerald-950 px-4 py-4"> <Text className="mb-4 text-xl font-bold text-emerald-100">Pending uploads</Text>
{records.length === 0 ? ( <View className="flex-1 items-center justify-center px-6"> <Text className="text-center text-base text-emerald-300"> There are no pending uploads, get to touching fluffy tail </Text> </View> ) : profilesLoading ? ( <View className="flex-1 items-center justify-center"> <ActivityIndicator color="#6ee7b7" /> <Text className="mt-2 text-emerald-300">Loading pending uploads...</Text> </View> ) : ( <FlatList className="w-full flex-1" data={entries} keyExtractor={(item, index) => `${item.did}-${index}`} renderItem={({ item, index }) => ( <View className={`w-full flex-row items-center gap-3 px-4 py-4 ${ index !== entries.length - 1 ? "border-b border-emerald-800" : "" }`}> {item.avatar ? ( <Image source={{ uri: item.avatar }} className="h-12 w-12 rounded-full bg-emerald-900" /> ) : ( <View className="h-12 w-12 rounded-full bg-emerald-800" /> )}
<View className="min-w-0 flex-1"> <Text numberOfLines={1} className="font-medium text-emerald-100"> {item.displayName} </Text>
<Text numberOfLines={1} className="text-sm text-emerald-400"> @{item.handle} </Text> </View> </View> )} contentContainerStyle={{ flexGrow: 1 }} showsVerticalScrollIndicator bounces={false} /> )}
<Pressable accessibilityRole="button" onPress={publish} disabled={!agent || uploading || records.length === 0 || profilesLoading} className={`mt-4 w-full items-center rounded-lg py-4 ${ !agent || uploading || records.length === 0 || profilesLoading ? "bg-emerald-900" : "bg-emerald-700" }`}> <Text className="text-base font-bold text-white"> {uploading ? "Uploading..." : "Upload?"} </Text> </Pressable> </View> );}