fiddy/apps/web/features/entries/components/entries-list.tsx

108 lines
5.3 KiB
TypeScript

"use client";
import type { Entry } from "@/lib/shared/types";
type EntriesListProps = {
activeGroupId: number | null;
loading: boolean;
entries: Entry[];
visibleEntries: Entry[];
activeFilterCount: number;
onOpenDetails: (entry: Entry, index: number) => void;
onClearFilters: () => void;
};
export default function EntriesList({
activeGroupId,
loading,
entries,
visibleEntries,
activeFilterCount,
onOpenDetails,
onClearFilters
}: EntriesListProps) {
return (
<div className="mt-3 space-y-2">
{!activeGroupId ? (
<div className="text-sm text-muted">Select a group to view entries.</div>
) : loading ? (
<div className="space-y-2">
{[0, 1, 2].map(row => (
<div key={row} className="rounded-lg border border-accent-weak bg-panel px-3 py-3">
<div className="animate-pulse space-y-2">
<div className="h-4 w-28 rounded bg-surface" />
<div className="h-3 w-40 rounded bg-surface" />
<div className="flex flex-wrap gap-2">
<div className="h-5 w-14 rounded-full bg-surface" />
<div className="h-5 w-12 rounded-full bg-surface" />
<div className="h-5 w-16 rounded-full bg-surface" />
</div>
</div>
</div>
))}
</div>
) : entries.length ? (
visibleEntries.length ? (
visibleEntries.map((entry, index) => {
const tags = entry.tags ?? [];
const mobileTagLimit = 2;
const mobileTags = tags.slice(0, mobileTagLimit);
const extraTagCount = Math.max(tags.length - mobileTagLimit, 0);
return (
<div
key={entry.id}
className="flex items-center justify-between rounded-lg border border-accent-weak bg-panel px-3 py-2 text-sm transition hover:border-accent hover:bg-accent-soft"
onClick={() => onOpenDetails(entry, index)}
>
<div className="flex flex-col gap-1">
<div className="text-base font-semibold">${entry.amountDollars.toFixed(2)}</div>
<div className="text-xs text-muted">
{new Date(entry.occurredAt).toISOString().slice(0, 10)} - {entry.necessity}
</div>
</div>
{tags.length ? (
<>
<div className="flex flex-wrap justify-end gap-2 md:hidden">
{mobileTags.map(tag => (
<span key={tag} className="rounded-full border border-accent-weak bg-accent-soft px-2 py-0.5 text-xs">
#{tag}
</span>
))}
{extraTagCount ? (
<span className="rounded-full border border-accent-weak bg-panel px-2 py-0.5 text-xs text-soft">
{extraTagCount} more...
</span>
) : null}
</div>
<div className="hidden flex-wrap justify-end gap-2 md:flex">
{tags.map(tag => (
<span key={tag} className="rounded-full border border-accent-weak bg-accent-soft px-2 py-0.5 text-xs">
#{tag}
</span>
))}
</div>
</>
) : (
<span className="rounded-full border border-accent-weak px-2 py-0.5 text-xs text-soft">No tags</span>
)}
</div>
);
})
) : (
<div className="space-y-2 text-sm text-muted">
<div>No matching entries.</div>
{activeFilterCount ? (
<button type="button" className="rounded-lg btn-outline-accent px-3 py-1 text-xs" onClick={onClearFilters}>
Clear filters
</button>
) : null}
</div>
)
) : (
<div className="text-sm text-muted">No entries yet.</div>
)}
</div>
);
}