commit
449caefa18
3 changed files with 374 additions and 83 deletions
|
|
@ -204,7 +204,7 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
|
|||
user.role === UserRole.SUPERADMIN) && (
|
||||
<button
|
||||
onClick={() => {
|
||||
onNavigate("settings");
|
||||
onNavigate("configuracoes");
|
||||
setIsAccountDropdownOpen(false);
|
||||
}}
|
||||
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
|
||||
|
|
@ -385,7 +385,7 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
|
|||
user.role === UserRole.SUPERADMIN) && (
|
||||
<button
|
||||
onClick={() => {
|
||||
onNavigate("settings");
|
||||
onNavigate("configuracoes");
|
||||
setIsAccountDropdownOpen(false);
|
||||
}}
|
||||
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import {
|
|||
Building2,
|
||||
Calendar,
|
||||
MapPin,
|
||||
X,
|
||||
UserCheck,
|
||||
UserX,
|
||||
} from "lucide-react";
|
||||
import { useAuth } from "../contexts/AuthContext";
|
||||
import { useData } from "../contexts/DataContext";
|
||||
|
|
@ -24,6 +27,125 @@ interface DashboardProps {
|
|||
initialView?: "list" | "create";
|
||||
}
|
||||
|
||||
interface Professional {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
avatar: string;
|
||||
role: "Fotógrafo" | "Cinegrafista" | "Recepcionista";
|
||||
availability: {
|
||||
[date: string]: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// Mock de profissionais cadastrados
|
||||
const MOCK_PHOTOGRAPHERS: Professional[] = [
|
||||
{
|
||||
id: "photographer-1",
|
||||
name: "Carlos Silva",
|
||||
email: "carlos@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=carlos",
|
||||
role: "Fotógrafo",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": true,
|
||||
"2025-12-15": false,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "photographer-2",
|
||||
name: "Ana Santos",
|
||||
email: "ana@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=ana",
|
||||
role: "Fotógrafo",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": false,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "photographer-3",
|
||||
name: "João Oliveira",
|
||||
email: "joao@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=joao",
|
||||
role: "Cinegrafista",
|
||||
availability: {
|
||||
"2025-12-05": false,
|
||||
"2025-12-10": true,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "photographer-4",
|
||||
name: "Maria Costa",
|
||||
email: "maria@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=maria",
|
||||
role: "Fotógrafo",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": true,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "photographer-5",
|
||||
name: "Pedro Alves",
|
||||
email: "pedro@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=pedro",
|
||||
role: "Cinegrafista",
|
||||
availability: {
|
||||
"2025-12-05": false,
|
||||
"2025-12-10": false,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "receptionist-1",
|
||||
name: "Julia Mendes",
|
||||
email: "julia@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=julia",
|
||||
role: "Recepcionista",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": true,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "receptionist-2",
|
||||
name: "Rafael Souza",
|
||||
email: "rafael@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=rafael",
|
||||
role: "Recepcionista",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": true,
|
||||
"2025-12-15": false,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "videographer-1",
|
||||
name: "Lucas Ferreira",
|
||||
email: "lucas@photum.com",
|
||||
avatar: "https://i.pravatar.cc/150?u=lucas",
|
||||
role: "Cinegrafista",
|
||||
availability: {
|
||||
"2025-12-05": true,
|
||||
"2025-12-10": false,
|
||||
"2025-12-15": true,
|
||||
"2025-12-20": true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const Dashboard: React.FC<DashboardProps> = ({
|
||||
initialView = "list",
|
||||
}) => {
|
||||
|
|
@ -50,6 +172,7 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
timeRange: '',
|
||||
type: '',
|
||||
});
|
||||
const [isTeamModalOpen, setIsTeamModalOpen] = useState(false);
|
||||
|
||||
// Reset view when initialView prop changes
|
||||
useEffect(() => {
|
||||
|
|
@ -157,17 +280,14 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
};
|
||||
|
||||
const handleManageTeam = () => {
|
||||
setIsTeamModalOpen(true);
|
||||
};
|
||||
|
||||
const togglePhotographer = (photographerId: string) => {
|
||||
if (!selectedEvent) return;
|
||||
const newId = window.prompt(
|
||||
"ID do Fotógrafo para adicionar (ex: photographer-1):",
|
||||
"photographer-1"
|
||||
);
|
||||
if (newId) {
|
||||
assignPhotographer(selectedEvent.id, newId);
|
||||
alert("Fotógrafo atribuído com sucesso!");
|
||||
assignPhotographer(selectedEvent.id, photographerId);
|
||||
const updated = events.find((e) => e.id === selectedEvent.id);
|
||||
if (updated) setSelectedEvent(updated);
|
||||
}
|
||||
};
|
||||
|
||||
// --- RENDERS PER ROLE ---
|
||||
|
|
@ -588,18 +708,21 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
|
||||
{selectedEvent.photographerIds.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{selectedEvent.photographerIds.map((id, idx) => (
|
||||
{selectedEvent.photographerIds.map((id) => {
|
||||
const photographer = MOCK_PHOTOGRAPHERS.find(p => p.id === id);
|
||||
return (
|
||||
<div key={id} className="flex items-center gap-2 text-sm">
|
||||
<div
|
||||
className="w-8 h-8 rounded-full border-2 border-gray-200 bg-gray-300 flex-shrink-0"
|
||||
style={{
|
||||
backgroundImage: `url(https://i.pravatar.cc/100?u=${id})`,
|
||||
backgroundImage: `url(${photographer?.avatar || `https://i.pravatar.cc/100?u=${id}`})`,
|
||||
backgroundSize: "cover",
|
||||
}}
|
||||
></div>
|
||||
<span className="text-gray-700">{id}</span>
|
||||
<span className="text-gray-700">{photographer?.name || id}</span>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-400 italic">
|
||||
|
|
@ -614,6 +737,178 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Modal de Gerenciamento de Equipe */}
|
||||
{isTeamModalOpen && selectedEvent && (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-2xl shadow-2xl max-w-6xl w-full max-h-[90vh] overflow-hidden flex flex-col">
|
||||
{/* Header */}
|
||||
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 flex justify-between items-center">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white mb-1">
|
||||
Gerenciar Equipe
|
||||
</h2>
|
||||
<p className="text-white/80 text-sm">
|
||||
{selectedEvent.name} - {new Date(selectedEvent.date + 'T00:00:00').toLocaleDateString('pt-BR')}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsTeamModalOpen(false)}
|
||||
className="text-white hover:bg-white/20 rounded-full p-2 transition-colors"
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="flex-1 overflow-auto p-6">
|
||||
<div className="mb-4">
|
||||
<p className="text-sm text-gray-600">
|
||||
Profissionais disponíveis para a data <strong>{new Date(selectedEvent.date + 'T00:00:00').toLocaleDateString('pt-BR')}</strong>. Clique em "Adicionar" para atribuir ao evento.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tabela de Profissionais */}
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-gray-50 border-b-2 border-gray-200">
|
||||
<th className="text-left p-4 font-semibold text-gray-700">
|
||||
Profissional
|
||||
</th>
|
||||
<th className="text-center p-4 font-semibold text-gray-700">
|
||||
Função
|
||||
</th>
|
||||
<th className="text-center p-4 font-semibold text-gray-700">
|
||||
E-mail
|
||||
</th>
|
||||
<th className="text-center p-4 font-semibold text-gray-700">
|
||||
Status
|
||||
</th>
|
||||
<th className="text-center p-4 font-semibold text-gray-700">
|
||||
Ação
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{MOCK_PHOTOGRAPHERS
|
||||
.filter((photographer) => {
|
||||
const isAssigned = selectedEvent.photographerIds.includes(photographer.id);
|
||||
const isAvailable = photographer.availability[selectedEvent.date] ?? false;
|
||||
return isAvailable || isAssigned;
|
||||
})
|
||||
.map((photographer) => {
|
||||
const isAssigned = selectedEvent.photographerIds.includes(photographer.id);
|
||||
const isAvailable = photographer.availability[selectedEvent.date] ?? false;
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={photographer.id}
|
||||
className="border-b border-gray-100 hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
{/* Profissional */}
|
||||
<td className="p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className="w-10 h-10 rounded-full border-2 border-gray-200 bg-gray-300 flex-shrink-0"
|
||||
style={{
|
||||
backgroundImage: `url(${photographer.avatar})`,
|
||||
backgroundSize: "cover",
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-900">
|
||||
{photographer.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
ID: {photographer.id}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
{/* Função */}
|
||||
<td className="p-4 text-center">
|
||||
<span className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
|
||||
{photographer.role}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
{/* E-mail */}
|
||||
<td className="p-4 text-center text-sm text-gray-600">
|
||||
{photographer.email}
|
||||
</td>
|
||||
|
||||
{/* Status */}
|
||||
<td className="p-4 text-center">
|
||||
{isAssigned ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-brand-gold/20 text-brand-black rounded-full text-xs font-medium">
|
||||
<CheckCircle size={14} />
|
||||
Atribuído
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-green-100 text-green-800 rounded-full text-xs font-medium">
|
||||
<UserCheck size={14} />
|
||||
Disponível
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* Ação */}
|
||||
<td className="p-4 text-center">
|
||||
<button
|
||||
onClick={() => togglePhotographer(photographer.id)}
|
||||
disabled={!isAvailable && !isAssigned}
|
||||
className={`px-4 py-2 rounded-lg font-medium text-sm transition-colors ${
|
||||
isAssigned
|
||||
? "bg-red-100 text-red-700 hover:bg-red-200"
|
||||
: isAvailable
|
||||
? "bg-brand-gold text-white hover:bg-[#a5bd2e]"
|
||||
: "bg-gray-100 text-gray-400 cursor-not-allowed"
|
||||
}`}
|
||||
>
|
||||
{isAssigned ? "Remover" : "Adicionar"}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{MOCK_PHOTOGRAPHERS.filter((p) => {
|
||||
const isAssigned = selectedEvent.photographerIds.includes(p.id);
|
||||
const isAvailable = p.availability[selectedEvent.date] ?? false;
|
||||
return isAvailable || isAssigned;
|
||||
}).length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={5} className="p-8 text-center">
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<UserX size={48} className="text-gray-300" />
|
||||
<p className="text-gray-500 font-medium">
|
||||
Nenhum profissional disponível para esta data
|
||||
</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
Tente selecionar outra data ou entre em contato com a equipe
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="border-t border-gray-200 p-6 bg-gray-50 flex justify-end gap-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsTeamModalOpen(false)}
|
||||
>
|
||||
Fechar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -192,41 +192,41 @@ export const FinancePage: React.FC = () => {
|
|||
|
||||
{/* Stats Cards */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 md:gap-6 mb-6 sm:mb-8">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-sm text-gray-600">Receitas</p>
|
||||
<TrendingUp className="text-green-600" size={24} />
|
||||
<p className="text-xs sm:text-sm text-gray-600">Receitas</p>
|
||||
<TrendingUp className="text-green-600" size={20} />
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-green-600">{formatCurrency(totalIncome)}</p>
|
||||
<p className="text-2xl sm:text-3xl font-bold text-green-600">{formatCurrency(totalIncome)}</p>
|
||||
<p className="text-xs text-gray-500 mt-1">Pagamentos recebidos</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-sm text-gray-600">Despesas</p>
|
||||
<TrendingDown className="text-red-600" size={24} />
|
||||
<p className="text-xs sm:text-sm text-gray-600">Despesas</p>
|
||||
<TrendingDown className="text-red-600" size={20} />
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-red-600">{formatCurrency(totalExpense)}</p>
|
||||
<p className="text-2xl sm:text-3xl font-bold text-red-600">{formatCurrency(totalExpense)}</p>
|
||||
<p className="text-xs text-gray-500 mt-1">Gastos do período</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-sm text-gray-600">Saldo</p>
|
||||
<DollarSign className="text-brand-gold" size={24} />
|
||||
<p className="text-xs sm:text-sm text-gray-600">Saldo</p>
|
||||
<DollarSign className="text-brand-gold" size={20} />
|
||||
</div>
|
||||
<p className={`text-3xl font-bold ${balance >= 0 ? 'text-brand-gold' : 'text-red-600'}`}>
|
||||
<p className={`text-2xl sm:text-3xl font-bold ${balance >= 0 ? 'text-brand-gold' : 'text-red-600'}`}>
|
||||
{formatCurrency(balance)}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 mt-1">Receitas - Despesas</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-sm text-gray-600">A Receber</p>
|
||||
<Clock className="text-yellow-600" size={24} />
|
||||
<p className="text-xs sm:text-sm text-gray-600">A Receber</p>
|
||||
<Clock className="text-yellow-600" size={20} />
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-yellow-600">{formatCurrency(pendingIncome)}</p>
|
||||
<p className="text-2xl sm:text-3xl font-bold text-yellow-600">{formatCurrency(pendingIncome)}</p>
|
||||
<p className="text-xs text-gray-500 mt-1">Pagamentos pendentes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -237,7 +237,7 @@ export const FinancePage: React.FC = () => {
|
|||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
onClick={() => setFilterType('all')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'all'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterType === 'all'
|
||||
? 'bg-brand-gold text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -246,7 +246,7 @@ export const FinancePage: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
onClick={() => setFilterType('income')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'income'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterType === 'income'
|
||||
? 'bg-green-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -255,7 +255,7 @@ export const FinancePage: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
onClick={() => setFilterType('expense')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'expense'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterType === 'expense'
|
||||
? 'bg-red-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -266,7 +266,7 @@ export const FinancePage: React.FC = () => {
|
|||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
onClick={() => setFilterStatus('all')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'all'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterStatus === 'all'
|
||||
? 'bg-brand-black text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -275,7 +275,7 @@ export const FinancePage: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
onClick={() => setFilterStatus('paid')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'paid'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterStatus === 'paid'
|
||||
? 'bg-green-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -284,7 +284,7 @@ export const FinancePage: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
onClick={() => setFilterStatus('pending')}
|
||||
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'pending'
|
||||
className={`px-3 sm:px-4 py-1.5 sm:py-2 rounded-md text-xs sm:text-sm font-medium transition-colors ${filterStatus === 'pending'
|
||||
? 'bg-yellow-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
|
|
@ -297,13 +297,13 @@ export const FinancePage: React.FC = () => {
|
|||
|
||||
{/* Transactions List */}
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold">Transações</h2>
|
||||
<div className="p-4 sm:p-6 border-b border-gray-200">
|
||||
<h2 className="text-lg sm:text-xl font-semibold">Transações</h2>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-gray-200">
|
||||
{filteredTransactions.length === 0 ? (
|
||||
<div className="p-12 text-center text-gray-500">
|
||||
<div className="p-8 sm:p-12 text-center text-gray-500">
|
||||
<CreditCard size={48} className="mx-auto mb-4 text-gray-300" />
|
||||
<p>Nenhuma transação encontrada</p>
|
||||
</div>
|
||||
|
|
@ -311,12 +311,11 @@ export const FinancePage: React.FC = () => {
|
|||
filteredTransactions.map((transaction) => (
|
||||
<div
|
||||
key={transaction.id}
|
||||
className="p-6 hover:bg-gray-50 transition-colors"
|
||||
className="p-4 sm:p-6 hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<div className={`w-10 h-10 rounded-full flex items-center justify-center ${transaction.type === 'income' ? 'bg-green-100' : 'bg-red-100'
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
||||
<div className="flex items-start gap-3 flex-1">
|
||||
<div className={`w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 ${transaction.type === 'income' ? 'bg-green-100' : 'bg-red-100'
|
||||
}`}>
|
||||
{transaction.type === 'income' ? (
|
||||
<TrendingUp size={20} className="text-green-600" />
|
||||
|
|
@ -324,35 +323,32 @@ export const FinancePage: React.FC = () => {
|
|||
<TrendingDown size={20} className="text-red-600" />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-brand-black">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-sm sm:text-base text-brand-black">
|
||||
{transaction.description}
|
||||
</h3>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<div className="flex flex-wrap items-center gap-1.5 mt-1">
|
||||
<span className="text-xs text-gray-500">{transaction.category}</span>
|
||||
{transaction.client && (
|
||||
<>
|
||||
<span className="text-xs text-gray-300">•</span>
|
||||
<span className="text-xs text-gray-500">{transaction.client}</span>
|
||||
<span className="text-xs text-gray-500 truncate">{transaction.client}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-right">
|
||||
<p className={`text-lg font-bold ${transaction.type === 'income' ? 'text-green-600' : 'text-red-600'
|
||||
}`}>
|
||||
{transaction.type === 'income' ? '+' : '-'} {formatCurrency(transaction.amount)}
|
||||
</p>
|
||||
<div className="flex items-center gap-1 text-xs text-gray-500 mt-1">
|
||||
<Calendar size={12} />
|
||||
{formatDate(transaction.date)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between sm:justify-end gap-3 sm:gap-4 ml-13 sm:ml-0">
|
||||
<p className={`text-lg sm:text-xl font-bold ${transaction.type === 'income' ? 'text-green-600' : 'text-red-600'
|
||||
}`}>
|
||||
{transaction.type === 'income' ? '+' : '-'} {formatCurrency(transaction.amount)}
|
||||
</p>
|
||||
<div className="flex items-center gap-1.5">
|
||||
{getStatusIcon(transaction.status)}
|
||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getStatusColor(transaction.status)}`}>
|
||||
{getStatusLabel(transaction.status)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue