Files
sam-react-prod/src/components/accounting/TaxInvoiceManagement/CardHistoryModal.tsx

179 lines
6.0 KiB
TypeScript
Raw Normal View History

'use client';
/**
* ( in )
*
* - ManualEntryModal z-index로
* - + / +
* - : "카드 내역이 없습니다."
* - 테이블: 날짜, , , ,
* -
*/
import { useState, useCallback } from 'react';
import { toast } from 'sonner';
import { formatNumber } from '@/lib/utils/amount';
import { Search } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { getTodayString, getLocalDateString } from '@/lib/utils/date';
import { getCardHistory } from './actions';
import type { CardHistoryRecord } from './types';
interface CardHistoryModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onSelect: (record: CardHistoryRecord) => void;
}
export function CardHistoryModal({
open,
onOpenChange,
onSelect,
}: CardHistoryModalProps) {
const today = getTodayString();
const monthAgo = getLocalDateString(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000));
const [startDate, setStartDate] = useState(monthAgo);
const [endDate, setEndDate] = useState(today);
const [searchText, setSearchText] = useState('');
const [data, setData] = useState<CardHistoryRecord[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
const handleSearch = useCallback(async () => {
setIsLoading(true);
setHasSearched(true);
try {
const result = await getCardHistory({
startDate,
endDate,
search: searchText,
page: 1,
perPage: 50,
});
if (result.success) {
setData(result.data ?? []);
} else {
toast.error(result.error || '카드 내역 조회에 실패했습니다.');
}
} catch {
toast.error('서버 오류가 발생했습니다.');
} finally {
setIsLoading(false);
}
}, [startDate, endDate, searchText]);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[600px] max-h-[80vh] flex flex-col">
<DialogHeader>
<DialogTitle> </DialogTitle>
</DialogHeader>
{/* 검색 영역 */}
<div className="space-y-2">
{/* Row1: 날짜 범위 */}
<div className="flex items-center gap-2">
<DatePicker
value={startDate}
onChange={setStartDate}
className="flex-1"
/>
<span className="text-sm text-muted-foreground shrink-0">~</span>
<DatePicker
value={endDate}
onChange={setEndDate}
className="flex-1"
/>
</div>
{/* Row2: 검색어 + 조회 */}
<div className="flex items-center gap-2">
<Input
placeholder="가맹점/승인번호"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
className="flex-1 h-9 text-sm"
/>
<Button size="sm" onClick={handleSearch} disabled={isLoading}>
<Search className="h-4 w-4 mr-1" />
</Button>
</div>
</div>
{/* 테이블 영역 */}
<div className="flex-1 overflow-auto border rounded-md">
{!hasSearched ? (
<div className="flex items-center justify-center h-[200px] text-sm text-muted-foreground">
.
</div>
) : isLoading ? (
<div className="flex items-center justify-center h-[200px] text-sm text-muted-foreground">
...
</div>
) : data.length === 0 ? (
<div className="flex items-center justify-center h-[200px] text-sm text-muted-foreground">
.
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead className="text-center"></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
<TableHead className="text-center"></TableHead>
<TableHead className="text-center w-[70px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((item) => (
<TableRow key={item.id}>
<TableCell className="text-center text-sm">
{item.transactionDate}
</TableCell>
<TableCell className="text-sm">{item.merchantName}</TableCell>
<TableCell className="text-right text-sm font-medium">
{formatNumber(item.amount)}
</TableCell>
<TableCell className="text-center text-sm text-muted-foreground">
{item.approvalNumber}
</TableCell>
<TableCell className="text-center">
<Button
variant="outline"
size="sm"
className="h-7 px-2 text-xs"
onClick={() => onSelect(item)}
>
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</div>
</DialogContent>
</Dialog>
);
}