Changes
This commit is contained in:
parent
7b919272b5
commit
681cf5aa26
@ -3,12 +3,17 @@ import { Card } from '@/components/ui/card';
|
|||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
import { AlertCircle, TrendingUp, TrendingDown, Copy } from 'lucide-react';
|
import { AlertCircle, TrendingUp, TrendingDown, Copy } from 'lucide-react';
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
|
|
||||||
interface PreviewTransacoesProps {
|
interface PreviewTransacoesProps {
|
||||||
transacoes: TransacaoImportada[];
|
transacoes: TransacaoImportada[];
|
||||||
onCategoriaChange: (hash: string, categoria: string) => void;
|
onCategoriaChange: (hash: string, categoria: string) => void;
|
||||||
|
onSelectionChange: (hash: string, selected: boolean) => void;
|
||||||
|
onSelectAll: () => void;
|
||||||
|
onDeselectAll: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const categorias = [
|
const categorias = [
|
||||||
@ -26,11 +31,19 @@ const categorias = [
|
|||||||
'Outros'
|
'Outros'
|
||||||
];
|
];
|
||||||
|
|
||||||
export const PreviewTransacoes = ({ transacoes, onCategoriaChange }: PreviewTransacoesProps) => {
|
export const PreviewTransacoes = ({
|
||||||
|
transacoes,
|
||||||
|
onCategoriaChange,
|
||||||
|
onSelectionChange,
|
||||||
|
onSelectAll,
|
||||||
|
onDeselectAll
|
||||||
|
}: PreviewTransacoesProps) => {
|
||||||
const novas = transacoes.filter(t => !t.isDuplicada);
|
const novas = transacoes.filter(t => !t.isDuplicada);
|
||||||
const duplicadas = transacoes.filter(t => t.isDuplicada);
|
const duplicadas = transacoes.filter(t => t.isDuplicada);
|
||||||
const totalEntradas = novas.filter(t => t.tipo === 'entrada').reduce((sum, t) => sum + t.valor, 0);
|
const selecionadas = novas.filter(t => t.selecionada);
|
||||||
const totalSaidas = novas.filter(t => t.tipo === 'saida').reduce((sum, t) => sum + t.valor, 0);
|
const totalEntradas = selecionadas.filter(t => t.tipo === 'entrada').reduce((sum, t) => sum + t.valor, 0);
|
||||||
|
const totalSaidas = selecionadas.filter(t => t.tipo === 'saida').reduce((sum, t) => sum + t.valor, 0);
|
||||||
|
const todasSelecionadas = novas.length > 0 && novas.every(t => t.selecionada);
|
||||||
|
|
||||||
const formatCurrency = (value: number) => {
|
const formatCurrency = (value: number) => {
|
||||||
return new Intl.NumberFormat('pt-BR', {
|
return new Intl.NumberFormat('pt-BR', {
|
||||||
@ -99,11 +112,38 @@ export const PreviewTransacoes = ({ transacoes, onCategoriaChange }: PreviewTran
|
|||||||
|
|
||||||
{/* Tabela de transações */}
|
{/* Tabela de transações */}
|
||||||
<Card className="p-6">
|
<Card className="p-6">
|
||||||
<h3 className="text-lg font-semibold mb-4">Transações para Importar</h3>
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<h3 className="text-lg font-semibold">Transações para Importar</h3>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onSelectAll}
|
||||||
|
>
|
||||||
|
Selecionar Todas
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onDeselectAll}
|
||||||
|
>
|
||||||
|
Desmarcar Todas
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="max-h-96 overflow-y-auto">
|
<div className="max-h-96 overflow-y-auto">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
<TableHead className="w-12">
|
||||||
|
<Checkbox
|
||||||
|
checked={todasSelecionadas}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
if (checked) onSelectAll();
|
||||||
|
else onDeselectAll();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableHead>
|
||||||
<TableHead>Data</TableHead>
|
<TableHead>Data</TableHead>
|
||||||
<TableHead>Descrição</TableHead>
|
<TableHead>Descrição</TableHead>
|
||||||
<TableHead>Categoria</TableHead>
|
<TableHead>Categoria</TableHead>
|
||||||
@ -118,6 +158,15 @@ export const PreviewTransacoes = ({ transacoes, onCategoriaChange }: PreviewTran
|
|||||||
key={transacao.hash_unico}
|
key={transacao.hash_unico}
|
||||||
className={transacao.isDuplicada ? 'opacity-50' : ''}
|
className={transacao.isDuplicada ? 'opacity-50' : ''}
|
||||||
>
|
>
|
||||||
|
<TableCell>
|
||||||
|
<Checkbox
|
||||||
|
checked={transacao.selecionada ?? false}
|
||||||
|
disabled={transacao.isDuplicada}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
onSelectionChange(transacao.hash_unico, checked as boolean)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
<TableCell className="whitespace-nowrap">
|
<TableCell className="whitespace-nowrap">
|
||||||
{formatDate(transacao.data)}
|
{formatDate(transacao.data)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@ -49,7 +49,14 @@ export const useImportacaoExtrato = () => {
|
|||||||
|
|
||||||
// Verificar duplicatas
|
// Verificar duplicatas
|
||||||
const transacoesComDuplicatas = await verificarDuplicatas(transacoesParseadas);
|
const transacoesComDuplicatas = await verificarDuplicatas(transacoesParseadas);
|
||||||
setTransacoes(transacoesComDuplicatas);
|
|
||||||
|
// Marcar todas as não duplicadas como selecionadas por padrão
|
||||||
|
const transacoesComSelecao = transacoesComDuplicatas.map(t => ({
|
||||||
|
...t,
|
||||||
|
selecionada: !t.isDuplicada
|
||||||
|
}));
|
||||||
|
|
||||||
|
setTransacoes(transacoesComSelecao);
|
||||||
|
|
||||||
const duplicadas = transacoesComDuplicatas.filter(t => t.isDuplicada).length;
|
const duplicadas = transacoesComDuplicatas.filter(t => t.isDuplicada).length;
|
||||||
const novas = transacoesComDuplicatas.length - duplicadas;
|
const novas = transacoesComDuplicatas.length - duplicadas;
|
||||||
@ -117,6 +124,24 @@ export const useImportacaoExtrato = () => {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const atualizarSelecao = (hash: string, selecionada: boolean) => {
|
||||||
|
setTransacoes(transacoes.map(t =>
|
||||||
|
t.hash_unico === hash ? { ...t, selecionada } : t
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
const selecionarTodas = () => {
|
||||||
|
setTransacoes(transacoes.map(t =>
|
||||||
|
t.isDuplicada ? t : { ...t, selecionada: true }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
const desselecionarTodas = () => {
|
||||||
|
setTransacoes(transacoes.map(t =>
|
||||||
|
t.isDuplicada ? t : { ...t, selecionada: false }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
transacoes,
|
transacoes,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
@ -124,6 +149,9 @@ export const useImportacaoExtrato = () => {
|
|||||||
processarArquivo,
|
processarArquivo,
|
||||||
importar,
|
importar,
|
||||||
limpar,
|
limpar,
|
||||||
atualizarCategoria
|
atualizarCategoria,
|
||||||
|
atualizarSelecao,
|
||||||
|
selecionarTodas,
|
||||||
|
desselecionarTodas
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,18 @@ const ImportarExtrato = () => {
|
|||||||
const [resultadoDialog, setResultadoDialog] = useState(false);
|
const [resultadoDialog, setResultadoDialog] = useState(false);
|
||||||
const [logImportacao, setLogImportacao] = useState<LogImportacao | null>(null);
|
const [logImportacao, setLogImportacao] = useState<LogImportacao | null>(null);
|
||||||
|
|
||||||
const { transacoes, isProcessing, isImporting, processarArquivo, importar, limpar, atualizarCategoria } = useImportacaoExtrato();
|
const {
|
||||||
|
transacoes,
|
||||||
|
isProcessing,
|
||||||
|
isImporting,
|
||||||
|
processarArquivo,
|
||||||
|
importar,
|
||||||
|
limpar,
|
||||||
|
atualizarCategoria,
|
||||||
|
atualizarSelecao,
|
||||||
|
selecionarTodas,
|
||||||
|
desselecionarTodas
|
||||||
|
} = useImportacaoExtrato();
|
||||||
const { contas, isLoading, criar, recarregar } = useContasBancarias();
|
const { contas, isLoading, criar, recarregar } = useContasBancarias();
|
||||||
|
|
||||||
const handleFileSelect = async (file: File) => {
|
const handleFileSelect = async (file: File) => {
|
||||||
@ -55,8 +66,15 @@ const ImportarExtrato = () => {
|
|||||||
const tipoArquivo = detectarTipoArquivo(arquivo.name);
|
const tipoArquivo = detectarTipoArquivo(arquivo.name);
|
||||||
if (!tipoArquivo) return;
|
if (!tipoArquivo) return;
|
||||||
|
|
||||||
|
// Filtrar apenas transações selecionadas
|
||||||
|
const transacoesSelecionadas = transacoes.filter(t => t.selecionada && !t.isDuplicada);
|
||||||
|
|
||||||
|
if (transacoesSelecionadas.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const log = await importar(transacoes, contaSelecionada, arquivo.name, tipoArquivo);
|
const log = await importar(transacoesSelecionadas, contaSelecionada, arquivo.name, tipoArquivo);
|
||||||
setLogImportacao(log);
|
setLogImportacao(log);
|
||||||
setResultadoDialog(true);
|
setResultadoDialog(true);
|
||||||
|
|
||||||
@ -80,6 +98,7 @@ const ImportarExtrato = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const novasTransacoes = transacoes.filter(t => !t.isDuplicada);
|
const novasTransacoes = transacoes.filter(t => !t.isDuplicada);
|
||||||
|
const transacoesSelecionadas = transacoes.filter(t => t.selecionada && !t.isDuplicada);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-background via-background to-muted/20 p-6">
|
<div className="min-h-screen bg-gradient-to-br from-background via-background to-muted/20 p-6">
|
||||||
@ -154,6 +173,9 @@ const ImportarExtrato = () => {
|
|||||||
<PreviewTransacoes
|
<PreviewTransacoes
|
||||||
transacoes={transacoes}
|
transacoes={transacoes}
|
||||||
onCategoriaChange={atualizarCategoria}
|
onCategoriaChange={atualizarCategoria}
|
||||||
|
onSelectionChange={atualizarSelecao}
|
||||||
|
onSelectAll={selecionarTodas}
|
||||||
|
onDeselectAll={desselecionarTodas}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Card className="p-6">
|
<Card className="p-6">
|
||||||
@ -163,11 +185,11 @@ const ImportarExtrato = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleImportar}
|
onClick={handleImportar}
|
||||||
disabled={isImporting || novasTransacoes.length === 0}
|
disabled={isImporting || transacoesSelecionadas.length === 0}
|
||||||
size="lg"
|
size="lg"
|
||||||
>
|
>
|
||||||
<FileCheck className="w-5 h-5 mr-2" />
|
<FileCheck className="w-5 h-5 mr-2" />
|
||||||
{isImporting ? 'Importando...' : `Importar ${novasTransacoes.length} Transações`}
|
{isImporting ? 'Importando...' : `Importar ${transacoesSelecionadas.length} Transações`}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export interface TransacaoImportada {
|
|||||||
categoria?: string;
|
categoria?: string;
|
||||||
hash_unico: string;
|
hash_unico: string;
|
||||||
isDuplicada?: boolean;
|
isDuplicada?: boolean;
|
||||||
|
selecionada?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogImportacao {
|
export interface LogImportacao {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user