import { Feather } from "@expo/vector-icons"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import axios from "axios"; import React, { useState } from "react"; import { ActivityIndicator, Alert, FlatList, Platform, RefreshControl, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { PostCard } from "@/components/PostCard"; import { PostizPost, usePostiz } from "@/context/PostizContext"; import { useColors } from "@/hooks/useColors"; function extractError(err: unknown): string { if (axios.isAxiosError(err)) { const status = err.response?.status; const data = err.response?.data; if (data) { const body = typeof data === "string" ? data.slice(0, 200) : (data?.message ?? data?.error ?? JSON.stringify(data)).toString().slice(0, 200); return status ? `HTTP ${status}: ${body}` : body; } if (status) return `HTTP ${status} — ${err.message}`; if (err.message) return err.message; } if (err instanceof Error) return err.message; return "Unknown error"; } type FilterType = "all" | "QUEUE" | "PUBLISHED" | "ERROR" | "DRAFT"; const FILTERS: { key: FilterType; label: string }[] = [ { key: "all", label: "All" }, { key: "QUEUE", label: "Queue" }, { key: "PUBLISHED", label: "Published" }, { key: "DRAFT", label: "Draft" }, { key: "ERROR", label: "Error" }, ]; export default function PostsScreen() { const colors = useColors(); const insets = useSafeAreaInsets(); const { client, isConfigured } = usePostiz(); const queryClient = useQueryClient(); const [filter, setFilter] = useState("all"); const [refreshing, setRefreshing] = useState(false); const start = new Date(); start.setMonth(start.getMonth() - 3); const end = new Date(); end.setMonth(end.getMonth() + 6); const { data: posts, isLoading, error, refetch } = useQuery({ queryKey: ["posts-list", !!client], queryFn: async () => { if (!client) return []; const res = await client.get("posts", { params: { startDate: start.toISOString(), endDate: end.toISOString(), }, }); return Array.isArray(res.data) ? res.data : res.data?.posts ?? []; }, enabled: !!client, retry: 1, staleTime: 0, }); const filteredPosts = filter === "all" ? posts ?? [] : (posts ?? []).filter((p) => p.state === filter); const handleRefresh = async () => { setRefreshing(true); await refetch(); setRefreshing(false); }; const handleDelete = async (id: string) => { if (!client) return; try { await client.delete(`posts/${id}`); queryClient.setQueryData(["posts-list", true], (old) => (old ?? []).filter((p) => p.id !== id) ); queryClient.invalidateQueries({ queryKey: ["posts"] }); } catch (e: unknown) { const msg = extractError(e); Alert.alert("Delete failed", msg); } }; if (!isConfigured) { return ( Not Configured Add your API key in Settings ); } return ( item.key} showsHorizontalScrollIndicator={false} contentContainerStyle={styles.filterList} renderItem={({ item }) => ( setFilter(item.key)} activeOpacity={0.7} style={[ styles.filterChip, { backgroundColor: filter === item.key ? colors.primary : colors.secondary, borderColor: filter === item.key ? colors.primary : colors.border, }, ]} > {item.label} )} style={[styles.filterBar, { borderBottomColor: colors.border }]} /> {isLoading ? ( ) : error ? ( Failed to load {extractError(error)} refetch()} style={[styles.retryBtn, { backgroundColor: colors.primary }]} > Try Again ) : ( item.id} renderItem={({ item }) => ( )} refreshControl={ } contentInsetAdjustmentBehavior="automatic" showsVerticalScrollIndicator={false} ListEmptyComponent={ No posts {filter === "all" ? "No posts found in the last 3 months" : `No ${filter.toLowerCase()} posts`} } scrollEnabled={filteredPosts.length > 0} /> )} ); } const styles = StyleSheet.create({ container: { flex: 1 }, centered: { flex: 1, alignItems: "center", justifyContent: "center", gap: 10, paddingHorizontal: 32, }, filterBar: { borderBottomWidth: StyleSheet.hairlineWidth, flexGrow: 0 }, filterList: { paddingHorizontal: 16, paddingVertical: 10, gap: 8 }, filterChip: { paddingHorizontal: 14, paddingVertical: 6, borderRadius: 20, borderWidth: 1 }, filterText: { fontSize: 13, fontFamily: "Inter_500Medium" }, emptyState: { alignItems: "center", paddingTop: 64, gap: 10 }, emptyTitle: { fontSize: 18, fontFamily: "Inter_600SemiBold" }, emptyText: { fontSize: 14, fontFamily: "Inter_400Regular", textAlign: "center" }, retryBtn: { marginTop: 4, paddingHorizontal: 20, paddingVertical: 10, borderRadius: 10 }, retryText: { fontSize: 14, fontFamily: "Inter_600SemiBold" }, });