diff --git a/client/src/components/Budget/CostsPanel.tsx b/client/src/components/Budget/CostsPanel.tsx index e2f548757..820651cb0 100644 --- a/client/src/components/Budget/CostsPanel.tsx +++ b/client/src/components/Budget/CostsPanel.tsx @@ -1,17 +1,17 @@ import { Fragment, useState, useEffect, useMemo, useCallback } from 'react' import { useSearchParams } from 'react-router' -import { ArrowDown, ArrowUp, BarChart3, Plus, Search, ArrowRight, ArrowLeftRight, Check, RotateCcw, Pencil, Trash2, AlertCircle, Download, StickyNote, ChevronDown } from 'lucide-react' +import { ArrowDown, ArrowUp, BarChart3, Plus, Search, ArrowRight, ArrowLeftRight, Check, RotateCcw, Pencil, Trash2, AlertCircle, Download, StickyNote, ChevronDown, Receipt, Paperclip } from 'lucide-react' import { useTripStore } from '../../store/tripStore' import { useAuthStore } from '../../store/authStore' import { useSettingsStore } from '../../store/settingsStore' import { useCanDo } from '../../store/permissionsStore' import { useToast } from '../shared/Toast' import { useTranslation } from '../../i18n' -import { budgetApi } from '../../api/client' +import { budgetApi, filesApi } from '../../api/client' import { useExchangeRates } from '../../hooks/useExchangeRates' import { useIsMobile } from '../../hooks/useIsMobile' import { formatMoney, currencyDecimals, currencyLocale, localizeAmountInput, amountToInputString } from '../../utils/formatters' -import { downloadBlob } from '../../utils/fileDownload' +import { downloadBlob, openFile } from '../../utils/fileDownload' import Modal from '../shared/Modal' import CustomSelect from '../shared/CustomSelect' import { CustomDatePicker } from '../shared/CustomDateTimePicker' @@ -19,7 +19,8 @@ import { localToday } from '../Planner/today' import { SYMBOLS, currenciesWith, SPLIT_COLORS } from './BudgetPanel.constants' import { amountPattern, calculateTicketShares, hasTicketSplit, NOTE_MAX, payersBalanced, readTicketItems, readUserNote, rebalancePayers, splitEqualShares, writeTicketItems, type TicketItem } from './CostsPanel.helpers' import { COST_CATEGORY_LIST, catMeta } from './costsCategories' -import type { BudgetItem } from '../../types' +import { ReceiptPreviewModal } from './ReceiptPreviewModal' +import type { BudgetItem, BudgetItemReceipt } from '../../types' import type { TripMember } from './BudgetPanelMemberChips' import GuestBadge from '../shared/GuestBadge' import { NumericInput } from '../shared/NumericInput' @@ -84,6 +85,7 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps const [dayFilter, setDayFilter] = useState('') // '' = all days, else YYYY-MM-DD const [modalOpen, setModalOpen] = useState(false) const [editing, setEditing] = useState(null) + const [previewReceipts, setPreviewReceipts] = useState<{ receipts: BudgetItemReceipt[]; initialIndex: number } | null>(null) // One note open at a time: two expanded rows next to each other read as a mess, // and the point of the collapse is that the list stays scannable. const [expandedNoteId, setExpandedNoteId] = useState(null) @@ -492,6 +494,14 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps onSaved={() => { setEditingSettlement(null); setAddingPayment(false); loadSettlement() }} /> )} + {previewReceipts && ( + setPreviewReceipts(null)} + /> + )} +