import React, { useState } from "react";
import { Ban, Pencil, RotateCcw } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "./card";
import { Button } from "./button";
import { Spinner } from "./spinner";
import { Badge } from "./badge";
import { Chip } from "./chip";
import { CategoryEditDialog, type CategoryItem } from "./category-edit-dialog";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "./tooltip";
import { cn } from "@/lib/utils";
import { formatCurrency } from "@/lib/format-currency";
import { formatDateShort } from "@/lib/format-date";
// ─── Types ───────────────────────────────────────────────────────────────────
export interface DashboardTransaction {
id: string;
/** ISO date string — "2024-04-15" or full ISO */
date: string;
description: string;
/** Optional merchant / location sub-label */
merchant?: string;
/** Signed dollar amount — positive = credit, negative = debit */
amount: number;
/** Display label for the category chip */
category?: string;
/** Category ID used for filter matching */
categoryId?: string;
/** User-overridden category name — displayed instead of `category` when set */
editedCategoryName?: string;
/** When true, the row is excluded from calculations (dimmed, amount struck through) */
isExcluded?: boolean;
}
export type { CategoryItem };
export interface DashboardTransactionsTableProps {
transactions?: DashboardTransaction[];
title?: string;
/** Show a "Load More" button when more pages are available */
hasNextPage?: boolean;
isLoadingMore?: boolean;
onLoadMore?: () => void;
isLoading?: boolean;
className?: string;
/**
* Active category filter ID. Rows whose categoryId does not match are dimmed.
* Pass null / undefined to show all rows at full opacity.
*/
selectedCategoryId?: string | null;
/**
* Category tree for the built-in CategoryEditDialog.
* When provided, clicking a category chip opens the dialog inline.
*/
categories?: CategoryItem[];
/**
* Called after the user saves a category change via the built-in dialog.
*/
onCategoryChange?: (
transactionId: string,
categoryId: string,
applyToFuture: boolean,
) => void;
/**
* When provided, each row shows an exclude/restore icon button that toggles
* whether the transaction is counted in calculations.
*/
onToggleExclude?: (transaction: DashboardTransaction) => void;
/**
* Show or hide the card header (title + tab row).
* Set to `false` when the surrounding layout already provides context.
* Defaults to `true`.
*/
showHeader?: boolean;
/**
* Show or hide the "Account Transaction" underlined tab below the title.
* Set to `false` when the surrounding layout already provides tab context.
* Defaults to `true`.
*/
showTab?: boolean;
/**
* Colour scheme for the editable category chip hover state.
* - `"primary"` (default) — green hover
* - `"secondary"` — dark navy hover; use when the surrounding context uses the secondary palette (e.g. expense view)
*/
colorScheme?: "primary" | "secondary";
}
// ─── Category chip ────────────────────────────────────────────────────────────
function CategoryChip({
label,
canEdit,
colorScheme = "primary",
onClick,
}: {
label: string;
canEdit: boolean;
colorScheme?: "primary" | "secondary";
onClick?: () => void;
}) {
if (canEdit) {
return (
{formatDateShort(tx.date)}
{tx.description}
{tx.merchant && ({tx.merchant}
)} {categoryLabel && (No transactions found
) : (