import { router } from "expo-router"; import { useState } from "react"; import { Pressable, RefreshControl, ScrollView, StyleSheet, Text, View, } from "react-native"; import { AppBackground } from "@/components/AppBackground"; import { FilterChip } from "@/components/FilterChip"; import { FloatingActionButton } from "@/components/FloatingActionButton"; import { GlassSurface } from "@/components/GlassSurface"; import { LoadingScreen } from "@/components/LoadingScreen"; import { PageHeader } from "@/components/PageHeader"; import { TabPage } from "@/components/TabPage"; import { TabScrollView } from "@/components/TabScrollView"; import { fonts, spacing } from "@/constants/theme"; import { useAppTheme } from "@/contexts/ThemeContext"; import { formatCurrency } from "@/lib/format"; import type { ThemeColors } from "@/lib/theme-palette"; import { useThemedStyles } from "@/lib/use-themed-styles"; import { api } from "@/lib/trpc"; type EntityTab = "clients" | "businesses"; const tabs: Array<{ label: string; value: EntityTab }> = [ { label: "Clients", value: "clients" }, { label: "Businesses", value: "businesses" }, ]; export default function EntitiesScreen() { const { colors } = useAppTheme(); const styles = useThemedStyles(createEntitiesStyles); const [tab, setTab] = useState("clients"); const clientsQuery = api.clients.getAll.useQuery(); const businessesQuery = api.businesses.getAll.useQuery(); const activeQuery = tab === "clients" ? clientsQuery : businessesQuery; const isLoading = clientsQuery.isLoading || (tab === "businesses" && businessesQuery.isLoading); if (isLoading) { return ; } if (activeQuery.error) { return ( Could not load {tab} {activeQuery.error.message} ); } const clients = clientsQuery.data ?? []; const businesses = businessesQuery.data ?? []; function refresh() { if (tab === "clients") void clientsQuery.refetch(); else void businessesQuery.refetch(); } return ( } refreshControl={ } > {tabs.map((item) => ( setTab(item.value)} /> ))} {tab === "clients" ? ( clients.length === 0 ? ( No clients yet Add a client to start creating invoices. ) : ( clients.map((client) => ( router.push(`/(app)/entities/clients/${client.id}`)} > {client.name} {client.email ? ( {client.email} ) : null} {client.defaultHourlyRate != null ? ( {formatCurrency(client.defaultHourlyRate, client.currency ?? "USD")} /hr ) : null} )) ) ) : businesses.length === 0 ? ( No businesses yet Add your business profile for invoices and email sending. ) : ( businesses.map((business) => ( router.push(`/(app)/entities/businesses/${business.id}`)} > {business.name} {business.isDefault ? ( Default ) : null} {business.nickname ? ( {business.nickname} ) : null} {business.email ? {business.email} : null} )) )} router.push( tab === "clients" ? "/(app)/entities/clients/new" : "/(app)/entities/businesses/new", ) } /> ); } const createEntitiesStyles = (colors: ThemeColors, isDark: boolean) => StyleSheet.create({ tabScroll: { flexGrow: 0, marginBottom: spacing.sm, }, tabs: { gap: spacing.sm, paddingRight: spacing.md, }, card: {}, cardInner: { padding: spacing.md, gap: 4, }, nameRow: { flexDirection: "row", alignItems: "center", gap: spacing.sm, flexWrap: "wrap", }, name: { fontSize: 16, fontFamily: fonts.bodySemiBold, color: colors.foreground, }, badge: { fontSize: 11, fontFamily: fonts.bodySemiBold, color: colors.primary, backgroundColor: isDark ? "rgba(74, 222, 128, 0.15)" : colors.muted, paddingHorizontal: spacing.sm, paddingVertical: 2, borderRadius: 999, overflow: "hidden", }, meta: { fontSize: 14, fontFamily: fonts.body, color: colors.mutedForeground, }, empty: { padding: spacing.lg, alignItems: "center", gap: spacing.sm, }, emptyTitle: { fontSize: 18, fontFamily: fonts.bodySemiBold, color: colors.foreground, }, emptyText: { textAlign: "center", color: colors.mutedForeground, fontFamily: fonts.body, lineHeight: 20, }, errorBox: { flex: 1, justifyContent: "center", padding: spacing.lg, gap: spacing.sm, }, errorTitle: { fontSize: 18, fontFamily: fonts.bodySemiBold, color: colors.foreground, }, errorText: { color: colors.mutedForeground, fontFamily: fonts.body, lineHeight: 20, }, });