212 lines
8.0 KiB
TypeScript
212 lines
8.0 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
PlusIcon,
|
|
BanknotesIcon,
|
|
TagIcon,
|
|
CheckIcon,
|
|
XMarkIcon,
|
|
PencilSquareIcon,
|
|
TrashIcon,
|
|
BuildingLibraryIcon
|
|
} from '@heroicons/react/24/outline';
|
|
import { erpApi, FinancialCategory, BankAccount } from '@/lib/api-erp';
|
|
import { formatCurrency } from '@/lib/format';
|
|
import { toast } from 'react-hot-toast';
|
|
import {
|
|
PageHeader,
|
|
DataTable,
|
|
Input,
|
|
Card,
|
|
Tabs
|
|
} from "@/components/ui";
|
|
|
|
export default function ERPSettingsPage() {
|
|
return (
|
|
<div className="space-y-6">
|
|
<PageHeader
|
|
title="Configurações do ERP"
|
|
description="Gerencie categorias financeiras, contas bancárias e outras preferências do sistema."
|
|
/>
|
|
|
|
<Tabs
|
|
variant="pills"
|
|
items={[
|
|
{
|
|
label: 'Categorias Financeiras',
|
|
icon: <TagIcon className="w-4 h-4" />,
|
|
content: <CategorySettings />
|
|
},
|
|
{
|
|
label: 'Contas Bancárias',
|
|
icon: <BuildingLibraryIcon className="w-4 h-4" />,
|
|
content: <AccountSettings />
|
|
}
|
|
]}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function CategorySettings() {
|
|
const [categories, setCategories] = useState<FinancialCategory[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, []);
|
|
|
|
const fetchData = async () => {
|
|
try {
|
|
const data = await erpApi.getFinancialCategories();
|
|
setCategories(data || []);
|
|
} catch (error) {
|
|
toast.error('Erro ao carregar categorias');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<h3 className="text-lg font-bold text-zinc-900 dark:text-white">Categorias</h3>
|
|
<button
|
|
className="flex items-center gap-2 px-4 py-2 text-white rounded-xl font-bold shadow-lg hover:opacity-90 transition-all text-sm"
|
|
style={{ background: 'var(--gradient)' }}
|
|
>
|
|
<PlusIcon className="w-4 h-4" />
|
|
Nova Categoria
|
|
</button>
|
|
</div>
|
|
|
|
<Card noPadding className="overflow-hidden">
|
|
<DataTable
|
|
isLoading={loading}
|
|
data={categories}
|
|
columns={[
|
|
{
|
|
header: 'Nome',
|
|
accessor: (row) => (
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: row.color }} />
|
|
<span className="font-bold text-zinc-900 dark:text-white">{row.name}</span>
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
header: 'Tipo',
|
|
accessor: (row) => (
|
|
<span className={`px-2 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wider ${row.type === 'income' ? 'bg-emerald-100 text-emerald-700' : 'bg-rose-100 text-rose-700'}`}>
|
|
{row.type === 'income' ? 'Receita' : 'Despesa'}
|
|
</span>
|
|
)
|
|
},
|
|
{
|
|
header: 'Status',
|
|
accessor: (row) => (
|
|
<span className={`text-xs font-bold ${row.is_active ? 'text-emerald-500' : 'text-zinc-400'}`}>
|
|
{row.is_active ? 'Ativo' : 'Inativo'}
|
|
</span>
|
|
)
|
|
},
|
|
{
|
|
header: '',
|
|
className: 'text-right',
|
|
accessor: () => (
|
|
<div className="flex justify-end gap-2 opacity-0 group-hover:opacity-100 transition-all">
|
|
<button className="p-2 text-zinc-400 hover:text-brand-600 dark:hover:text-brand-400">
|
|
<PencilSquareIcon className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
]}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function AccountSettings() {
|
|
const [accounts, setAccounts] = useState<BankAccount[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, []);
|
|
|
|
const fetchData = async () => {
|
|
try {
|
|
const data = await erpApi.getBankAccounts();
|
|
setAccounts(data || []);
|
|
} catch (error) {
|
|
toast.error('Erro ao carregar contas');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<h3 className="text-lg font-bold text-zinc-900 dark:text-white">Contas Bancárias</h3>
|
|
<button
|
|
className="flex items-center gap-2 px-4 py-2 text-white rounded-xl font-bold shadow-lg hover:opacity-90 transition-all text-sm"
|
|
style={{ background: 'var(--gradient)' }}
|
|
>
|
|
<PlusIcon className="w-4 h-4" />
|
|
Nova Conta
|
|
</button>
|
|
</div>
|
|
|
|
<Card noPadding className="overflow-hidden">
|
|
<DataTable
|
|
isLoading={loading}
|
|
data={accounts}
|
|
columns={[
|
|
{
|
|
header: 'Nome da Conta',
|
|
accessor: (row) => (
|
|
<div className="flex flex-col">
|
|
<span className="font-bold text-zinc-900 dark:text-white">{row.name}</span>
|
|
<span className="text-xs text-zinc-400 font-bold uppercase">{row.bank_name}</span>
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
header: 'Saldo Atual',
|
|
className: 'text-right',
|
|
accessor: (row) => (
|
|
<span className="font-black text-zinc-900 dark:text-white">
|
|
{formatCurrency(row.current_balance)}
|
|
</span>
|
|
)
|
|
},
|
|
{
|
|
header: 'Status',
|
|
accessor: (row) => (
|
|
<span className={`text-xs font-bold ${row.is_active ? 'text-emerald-500' : 'text-zinc-400'}`}>
|
|
{row.is_active ? 'Ativo' : 'Inativo'}
|
|
</span>
|
|
)
|
|
},
|
|
{
|
|
header: '',
|
|
className: 'text-right',
|
|
accessor: () => (
|
|
<div className="flex justify-end gap-2 opacity-0 group-hover:opacity-100 transition-all">
|
|
<button className="p-2 text-zinc-400 hover:text-brand-600 dark:hover:text-brand-400">
|
|
<PencilSquareIcon className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
]}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|