diff --git a/src/app/transactions/page.tsx b/src/app/transactions/page.tsx index aacc346..64cf66c 100644 --- a/src/app/transactions/page.tsx +++ b/src/app/transactions/page.tsx @@ -2,7 +2,7 @@ import { useState, useCallback, Suspense } from "react"; import { useSearchParams } from "next/navigation"; -import { useTransactions, useBanks, useUpdateTransaction, useBulkAction, useTags, useStatement } from "@/lib/hooks"; +import { useTransactions, useBanks, useUpdateTransaction, useBulkAction, useTags, useStatement, useCreateRule } from "@/lib/hooks"; import { CATEGORIES, formatCategory } from "@/lib/categories"; import { SplitModal } from "@/components/split-modal"; import { TagPicker } from "@/components/tag-picker"; @@ -71,6 +71,80 @@ function EditableTypeBadge({ type, onSave }: { type: string; onSave: (t: string) ); } +// Prompt shown after a merchant/category edit — offers to save it as a rule +function SaveAsRulePrompt({ + tx, + field, + newValue, + onDone, +}: { + tx: { id: number; effective_merchant: string; description: string; bank_name: string }; + field: "category" | "merchant"; + newValue: string; + onDone: () => void; +}) { + const createRule = useCreateRule(); + const [saving, setSaving] = useState(false); + + // Build a sensible default rule from the transaction context + const merchantMatch = tx.effective_merchant || tx.description; + const defaultName = + field === "category" + ? `${merchantMatch} → ${formatCategory(newValue)}` + : `Rename ${tx.effective_merchant || tx.description} → ${newValue}`; + + const conditions = [ + { + field: "description", + operator: "contains", + value: (tx.effective_merchant || tx.description).split(" ")[0] ?? "", + }, + ]; + const actions = + field === "category" + ? { set_category: newValue } + : { set_merchant: newValue }; + + async function save() { + setSaving(true); + await createRule.mutateAsync({ name: defaultName, conditions, actions, enabled: true, priority: 0 }); + onDone(); + } + + return ( +
Save as rule?
++ Automatically apply this {field === "category" ? "category" : "merchant name"} to future matching transactions. +
+If description contains "{conditions[0].value}"
++ Then{" "} + {field === "category" + ? <>set category → {formatCategory(newValue)}> + : <>set merchant → {newValue}>} +
+