demo2
This commit is contained in:
@@ -443,26 +443,137 @@ export default function ExpensesPage() {
|
||||
</div>
|
||||
|
||||
{/* Action Messages */}
|
||||
{actionData?.success && actionData.message && (
|
||||
{actionData?.success && 'message' in actionData && actionData.message && (
|
||||
<div className="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded-lg">
|
||||
{actionData.message}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{actionData?.error && (
|
||||
{actionData && !actionData.success && 'error' in actionData && actionData.error && (
|
||||
<div className="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded-lg">
|
||||
{actionData.error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Expenses Table */}
|
||||
<DataTable
|
||||
data={expenses}
|
||||
columns={columns}
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPageChange={handlePageChange}
|
||||
/>
|
||||
<div className="bg-white rounded-lg shadow-sm border">
|
||||
{expenses.length === 0 ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="text-gray-400 text-lg mb-2">💰</div>
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||
لا توجد مصروفات
|
||||
</h3>
|
||||
<p className="text-gray-500">
|
||||
لم يتم العثور على أي مصروفات.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Desktop Table View */}
|
||||
<div className="hidden md:block">
|
||||
<DataTable
|
||||
data={expenses as any}
|
||||
columns={columns}
|
||||
emptyMessage="لم يتم العثور على أي مصروفات"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Mobile Card View */}
|
||||
<div className="md:hidden divide-y divide-gray-200">
|
||||
{expenses.map((expense: any) => {
|
||||
const categoryLabel = EXPENSE_CATEGORIES.find(c => c.value === expense.category)?.label;
|
||||
return (
|
||||
<div key={expense.id} className="p-4 hover:bg-gray-50">
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="flex-1">
|
||||
<div className="font-medium text-gray-900">{expense.description}</div>
|
||||
<div className="text-sm text-gray-500 mt-1">{categoryLabel || expense.category}</div>
|
||||
</div>
|
||||
<div className="text-lg font-semibold text-gray-900">
|
||||
{formatCurrency(expense.amount)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
<div>
|
||||
<span className="text-gray-600">تاريخ المصروف: </span>
|
||||
<span className="text-gray-900">{formatDate(expense.expenseDate)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-gray-600">تاريخ الإضافة: </span>
|
||||
<span className="text-gray-900">{formatDate(expense.createdDate)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleEditExpense(expense)}
|
||||
disabled={isLoading}
|
||||
className="w-full"
|
||||
>
|
||||
تعديل
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{totalPages > 1 && (
|
||||
<div className="px-4 py-3 border-t border-gray-200 bg-gray-50">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2 space-x-reverse">
|
||||
<button
|
||||
onClick={() => handlePageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1 || isLoading}
|
||||
className="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
السابق
|
||||
</button>
|
||||
|
||||
<div className="flex items-center space-x-1 space-x-reverse">
|
||||
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
||||
const page = i + 1;
|
||||
return (
|
||||
<button
|
||||
key={page}
|
||||
onClick={() => handlePageChange(page)}
|
||||
disabled={isLoading}
|
||||
className={`px-3 py-2 text-sm font-medium rounded-md ${
|
||||
currentPage === page
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'text-gray-500 bg-white border border-gray-300 hover:bg-gray-50'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
>
|
||||
{page}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => handlePageChange(currentPage + 1)}
|
||||
disabled={currentPage === totalPages || isLoading}
|
||||
className="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
التالي
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-gray-500">
|
||||
صفحة {currentPage} من {totalPages}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Create Expense Modal */}
|
||||
<Modal
|
||||
@@ -472,7 +583,7 @@ export default function ExpensesPage() {
|
||||
>
|
||||
<ExpenseForm
|
||||
onCancel={() => setShowCreateModal(false)}
|
||||
errors={actionData?.action === "create" ? actionData.errors : undefined}
|
||||
errors={actionData && 'errors' in actionData ? actionData.errors : undefined}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</Modal>
|
||||
@@ -487,7 +598,7 @@ export default function ExpensesPage() {
|
||||
<ExpenseForm
|
||||
expense={selectedExpense}
|
||||
onCancel={() => setShowEditModal(false)}
|
||||
errors={actionData?.action === "update" ? actionData.errors : undefined}
|
||||
errors={actionData && 'errors' in actionData ? actionData.errors : undefined}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user