whisper-money/resources/js/components/transactions/transaction-actions-menu.tsx

220 lines
8.2 KiB
TypeScript

import { categorize } from '@/actions/App/Http/Controllers/TransactionController';
import { Button } from '@/components/ui/button';
import { ButtonGroup } from '@/components/ui/button-group';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { useEncryptionKey } from '@/contexts/encryption-key-context';
import { useReEvaluateAllTransactions } from '@/hooks/use-re-evaluate-all-transactions';
import { type Account, type Bank } from '@/types/account';
import { type AutomationRule } from '@/types/automation-rule';
import { type Category } from '@/types/category';
import { type DecryptedTransaction } from '@/types/transaction';
import { Link } from '@inertiajs/react';
import { ChevronDown, Plus, Upload, WandSparkles } from 'lucide-react';
import { useState } from 'react';
import { toast } from 'sonner';
import { ImportTransactionsDrawer } from './import-transactions-drawer';
interface TransactionActionsMenuProps {
categories: Category[];
accounts: Account[];
banks: Bank[];
automationRules?: AutomationRule[];
onAddTransaction: () => void;
transactions: DecryptedTransaction[];
onReEvaluateComplete?: () => void;
}
export function TransactionActionsMenu({
categories,
accounts,
banks,
automationRules = [],
onAddTransaction,
transactions,
onReEvaluateComplete,
}: TransactionActionsMenuProps) {
const { isKeySet } = useEncryptionKey();
const [importDrawerOpen, setImportDrawerOpen] = useState(false);
const [isReEvaluating, setIsReEvaluating] = useState(false);
const { reEvaluateAll } = useReEvaluateAllTransactions();
const handleAddTransaction = () => {
if (!isKeySet) {
toast.error(
'Please unlock your encryption key to add transactions',
);
return;
}
onAddTransaction();
};
const handleOpenImportDrawer = () => {
if (!isKeySet) {
toast.error(
'Please unlock your encryption key to import transactions',
);
return;
}
setImportDrawerOpen(true);
};
const handleReEvaluateAll = async () => {
if (!isKeySet) {
toast.error(
'Please unlock your encryption key to re-evaluate transactions',
);
return;
}
if (!transactions.length) {
toast.error('No transactions to re-evaluate');
return;
}
setIsReEvaluating(true);
try {
await reEvaluateAll(
transactions,
categories,
accounts,
banks,
automationRules,
);
onReEvaluateComplete?.();
} finally {
setIsReEvaluating(false);
}
};
const uncategorizedCount = transactions.filter(
(t) => !t.category_id,
).length;
return (
<>
<ButtonGroup>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
className={
!isKeySet || uncategorizedCount === 0
? 'cursor-not-allowed opacity-50'
: ''
}
disabled={!isKeySet || uncategorizedCount === 0}
asChild={isKeySet && uncategorizedCount > 0}
>
{isKeySet && uncategorizedCount > 0 ? (
<Link href={categorize.url()}>
Categorize
{uncategorizedCount > 0 && (
<span className="ml-1 rounded-full bg-amber-100 px-1.5 py-0.5 text-xs font-medium text-amber-700 dark:bg-amber-900/30 dark:text-amber-400">
{uncategorizedCount}
</span>
)}
</Link>
) : (
<>Categorize</>
)}
</Button>
</TooltipTrigger>
<TooltipContent>
{!isKeySet
? 'Unlock encryption to categorize'
: uncategorizedCount === 0
? 'All transactions are categorized'
: `Categorize ${uncategorizedCount} transactions`}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
className={
!isKeySet
? 'cursor-not-allowed opacity-50'
: ''
}
onClick={handleAddTransaction}
aria-label="Add transaction"
>
<Plus className="h-5 w-5" />
Add Transaction
</Button>
</TooltipTrigger>
<TooltipContent>
{!isKeySet
? 'Unlock encryption to add transactions'
: 'Create a new transaction'}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<DropdownMenu>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="icon"
aria-label="More actions"
>
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent>More actions</TooltipContent>
</Tooltip>
</TooltipProvider>
<DropdownMenuContent align="end">
<DropdownMenuItem
onClick={handleOpenImportDrawer}
disabled={!isKeySet}
>
<Upload className="mr-2 h-4 w-4" />
Import Transactions
</DropdownMenuItem>
<DropdownMenuItem
onClick={handleReEvaluateAll}
disabled={
!isKeySet ||
isReEvaluating ||
!transactions.length
}
>
<WandSparkles className="mr-2 h-4 w-4" />
Re-evaluate All Expenses
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
<ImportTransactionsDrawer
open={importDrawerOpen}
onOpenChange={setImportDrawerOpen}
categories={categories}
accounts={accounts}
banks={banks}
automationRules={automationRules}
/>
</>
);
}