diff --git a/resources/js/components/cashflow/breakdown-card.test.tsx b/resources/js/components/cashflow/breakdown-card.test.tsx new file mode 100644 index 00000000..08901dac --- /dev/null +++ b/resources/js/components/cashflow/breakdown-card.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from '@testing-library/react'; +import type React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { BreakdownCard } from './breakdown-card'; + +vi.mock('@/components/ui/amount-display', () => ({ + AmountDisplay: ({ amountInCents }: { amountInCents: number }) => ( + {amountInCents} + ), +})); + +vi.mock('@/actions/App/Http/Controllers/TransactionController', () => ({ + index: () => ({ url: '/transactions' }), +})); + +vi.mock('@inertiajs/react', () => ({ + Link: ({ children, href }: { children: React.ReactNode; href: string }) => ( + {children} + ), + usePage: () => ({ props: { chartColorScheme: 'colorful' } }), +})); + +describe('BreakdownCard', () => { + it('renders uncategorized rows when the API returns a null category', () => { + render( + , + ); + + expect(screen.getByText('Uncategorized')).toBeInTheDocument(); + expect(screen.getByText('100%')).toBeInTheDocument(); + }); +}); diff --git a/resources/js/components/cashflow/breakdown-card.tsx b/resources/js/components/cashflow/breakdown-card.tsx index 6c7b5fe9..88ba5236 100644 --- a/resources/js/components/cashflow/breakdown-card.tsx +++ b/resources/js/components/cashflow/breakdown-card.tsx @@ -12,7 +12,11 @@ import { Progress } from '@/components/ui/progress'; import { BreakdownData } from '@/hooks/use-cashflow-data'; import { useChartColors } from '@/hooks/use-chart-color-scheme'; import { cn } from '@/lib/utils'; -import { getCategoryColorClasses } from '@/types/category'; +import { + type CategoryColor, + type CategoryIcon, + getCategoryColorClasses, +} from '@/types/category'; import { __ } from '@/utils/i18n'; import { Link } from '@inertiajs/react'; import { format } from 'date-fns'; @@ -27,6 +31,12 @@ interface BreakdownCardProps { period?: { from: Date; to: Date }; } +const fallbackCategory = { + name: __('Uncategorized'), + icon: 'HelpCircle' as CategoryIcon, + color: 'gray' as CategoryColor, +}; + export function BreakdownCard({ type, data, @@ -89,8 +99,9 @@ export function BreakdownCard({
{data.data.map((item, index) => { + const category = item.category ?? fallbackCategory; const Icon = (Icons[ - item.category.icon as keyof typeof Icons + category.icon as keyof typeof Icons ] || Icons.HelpCircle) as LucideIcon; const percentageChange = @@ -101,10 +112,10 @@ export function BreakdownCard({ : null; const categoryColor = getCategoryColorClasses( - item.category.color, + category.color, ); const chartColor = categoryBarColor( - item.category.color, + category.color, index, ); @@ -134,7 +145,7 @@ export function BreakdownCard({
- {item.category.name} + {category.name}
diff --git a/resources/js/hooks/use-cashflow-data.ts b/resources/js/hooks/use-cashflow-data.ts index 06971f69..9e859a1d 100644 --- a/resources/js/hooks/use-cashflow-data.ts +++ b/resources/js/hooks/use-cashflow-data.ts @@ -30,8 +30,8 @@ export interface TrendDataPoint { } export interface BreakdownItem { - category: Category; - category_id: string; + category: Category | null; + category_id: string | null; amount: number; percentage: number; previous_amount: number; diff --git a/vitest.config.ts b/vitest.config.ts index 9425f53a..2ef88467 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,9 +1,10 @@ +import { wayfinder } from '@laravel/vite-plugin-wayfinder'; import react from '@vitejs/plugin-react'; import { resolve } from 'path'; import { defineConfig } from 'vitest/config'; export default defineConfig({ - plugins: [react()], + plugins: [react(), wayfinder({ formVariants: true })], test: { environment: 'jsdom', globals: true,