import { useMemo, useState } from "react"; import { RefreshControl, StyleSheet, Text, View } from "react-native"; import { AppBackground } from "@/components/AppBackground"; import { LoadingScreen } from "@/components/LoadingScreen"; import { PageHeader } from "@/components/PageHeader"; import { SwipeableRow } from "@/components/SwipeableRow"; import { TabPage } from "@/components/TabPage"; import { TabScrollView } from "@/components/TabScrollView"; import { TimeEntryEditSheet } from "@/components/time-clock/TimeEntryEditSheet"; import { Card } from "@/components/ui/Card"; import { fonts, spacing } from "@/constants/theme"; import { useAppTheme } from "@/contexts/ThemeContext"; import { formatRunningTimerLabel } from "@/lib/time-clock"; import { formatTrpcErrorMessage } from "@/lib/trpc-errors"; import { api } from "@/lib/trpc"; import type { AppRouter } from "beenvoice/server/api/root"; import type { inferRouterOutputs } from "@trpc/server"; type TimeEntry = inferRouterOutputs["timeEntries"]["getAll"][number]; function groupByDate(entries: TimeEntry[]) { const groups = new Map(); for (const entry of entries) { const d = new Date(entry.startedAt); const key = d.toLocaleDateString(undefined, { weekday: "long", month: "long", day: "numeric", year: "numeric", }); const list = groups.get(key) ?? []; list.push(entry); groups.set(key, list); } return Array.from(groups.entries()); } export default function TimeEntriesScreen() { const { colors } = useAppTheme(); const [editEntryId, setEditEntryId] = useState(null); const entriesQuery = api.timeEntries.getAll.useQuery(); const completed = useMemo( () => (entriesQuery.data ?? []).filter((entry) => entry.endedAt), [entriesQuery.data], ); const grouped = useMemo(() => groupByDate(completed), [completed]); if (entriesQuery.isLoading) { return ; } if (entriesQuery.error) { return ( {formatTrpcErrorMessage(entriesQuery.error)} ); } return ( } refreshControl={ void entriesQuery.refetch()} tintColor={colors.primary} /> } > {grouped.length === 0 ? ( No completed entries yet. Start the timer from the Timer tab. ) : ( grouped.map(([label, entries]) => ( {entries.map((entry) => ( setEditEntryId(entry.id), }, ]} > {formatRunningTimerLabel(entry.description)} {entry.client?.name ?? "No client"} {entry.invoice ? ` · ${entry.invoice.invoicePrefix ?? "#"}${entry.invoice.invoiceNumber}` : " · not billed"} {entry.hours ?? "—"}h ))} )) )} setEditEntryId(null)} /> ); } const styles = StyleSheet.create({ row: { flexDirection: "row", gap: spacing.md, paddingVertical: spacing.sm, }, title: { fontFamily: fonts.bodySemiBold, fontSize: 14, }, });