Initial commit
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import Label from "@/app/(protected)/components/shared/Label";
|
||||
import { getPaymentsByObligationAction } from "@/app/lib/payments/actions";
|
||||
|
||||
export default function ObligationDetails({ obligations }) {
|
||||
const [expandedObligation, setExpandedObligation] = useState(null);
|
||||
const [obligationPayments, setObligationPayments] = useState({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// Group obligations by their reference (description + dueDate)
|
||||
const groupedObligations = obligations.reduce((acc, obligation) => {
|
||||
const key = `${obligation.description || "Pagamento"}_${obligation.dueDate || obligation.createdAt}`;
|
||||
if (!acc[key]) {
|
||||
acc[key] = {
|
||||
...obligation,
|
||||
users: [],
|
||||
};
|
||||
}
|
||||
acc[key].users.push(obligation);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const groupedList = Object.values(groupedObligations);
|
||||
|
||||
const fetchPaymentsForObligation = async (obligation) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await getPaymentsByObligationAction(obligation._id);
|
||||
if (result.success) {
|
||||
setObligationPayments(prev => ({
|
||||
...prev,
|
||||
[obligation._id]: result.data || [],
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching payments:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleExpand = (obligation) => {
|
||||
if (expandedObligation === obligation._id) {
|
||||
setExpandedObligation(null);
|
||||
} else {
|
||||
setExpandedObligation(obligation._id);
|
||||
if (!obligationPayments[obligation._id]) {
|
||||
fetchPaymentsForObligation(obligation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusBadge = (userObligation) => {
|
||||
const payments = obligationPayments[userObligation._id] || [];
|
||||
const hasVerified = payments.some(p => p.status === "verified");
|
||||
const hasPending = payments.some(p => p.status === "pending_verification");
|
||||
|
||||
if (hasVerified) {
|
||||
return <Label color="emerald" size="sm">✓ Pago</Label>;
|
||||
}
|
||||
if (hasPending) {
|
||||
return <Label color="blue" size="sm">Aguardando Verificação</Label>;
|
||||
}
|
||||
return <Label color="amber" size="sm">Aguardando Pagamento</Label>;
|
||||
};
|
||||
|
||||
if (obligations.length === 0) {
|
||||
return (
|
||||
<div className="bg-white dark:bg-neutral-800 rounded-lg shadow p-6 text-center text-gray-500 dark:text-gray-200 label-dark">
|
||||
Nenhuma obrigação de pagamento criada ainda.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{groupedList.map((group) => (
|
||||
<div
|
||||
key={group._id}
|
||||
className="bg-white dark:bg-neutral-800 rounded-lg shadow overflow-hidden"
|
||||
>
|
||||
{/* Group Header */}
|
||||
<div
|
||||
className="p-4 cursor-pointer hover:bg-gray-50 dark:hover:bg-neutral-700/50 transition-colors"
|
||||
onClick={() => handleToggleExpand(group)}
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900 dark:text-neutral-100">
|
||||
{group.description || "Pagamento"}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-200 label-dark">
|
||||
Vencimento: {format(new Date(group.dueDate || group.createdAt), "dd/MM/yyyy", { locale: ptBR })}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-right">
|
||||
<p className="text-sm text-gray-500 dark:text-gray-200 label-dark">
|
||||
{group.users.length} {group.users.length === 1 ? "aluno" : "alunos"}
|
||||
</p>
|
||||
<p className="text-lg font-bold text-gray-900 dark:text-neutral-100">
|
||||
R$ {group.amount?.toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-gray-400 dark:text-neutral-500">
|
||||
{expandedObligation === group._id ? "▼" : "▶"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expanded Details */}
|
||||
{expandedObligation === group._id && (
|
||||
<div className="border-t border-gray-200 dark:border-neutral-700">
|
||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-neutral-700">
|
||||
<thead className="bg-gray-50 dark:bg-neutral-700">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-200 label-dark uppercase tracking-wider">
|
||||
Aluno
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-200 label-dark uppercase tracking-wider">
|
||||
Email
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-200 label-dark uppercase tracking-wider">
|
||||
Valor
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-200 label-dark uppercase tracking-wider">
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white dark:bg-neutral-800 divide-y divide-gray-200 dark:divide-neutral-700">
|
||||
{group.users.map((userObligation) => (
|
||||
<tr
|
||||
key={userObligation._id}
|
||||
className="hover:bg-gray-50 dark:hover:bg-neutral-700/50"
|
||||
>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-neutral-100">
|
||||
{userObligation.userId?.fullName || "N/A"}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-200 label-dark">
|
||||
{userObligation.userId?.email || "N/A"}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-neutral-100 font-medium">
|
||||
R$ {userObligation.amount?.toFixed(2) || "0.00"}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
{getStatusBadge(userObligation)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user