refactor: Update BillingManager UI components for improved styling and user experience, including badge colors, button styles, and status selection method.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m3s

This commit is contained in:
2025-12-06 03:00:35 +07:00
parent d60eb96d00
commit e086d04131
+59 -38
View File
@@ -426,27 +426,32 @@ function BillingManager() {
if (days < 0) {
return (
<span className="badge bg-danger">
Просрочено {Math.abs(days)} дн.
<span className="badge bg-red-lt text-red">
<IconAlertTriangle size={12} className="me-1" />
{Math.abs(days)} дн. назад
</span>
);
} else if (days === 0) {
return <span className="badge bg-danger">Сегодня!</span>;
return (
<span className="badge bg-red-lt text-red">
Сегодня
</span>
);
} else if (days <= 7) {
return (
<span className="badge bg-warning text-dark">
<span className="badge bg-yellow-lt text-yellow">
{days} дн.
</span>
);
} else if (days <= 30) {
return (
<span className="badge bg-blue-lt text-blue">
<span className="badge bg-azure-lt text-azure">
{days} дн.
</span>
);
} else {
return (
<span className="text-muted small">
<span className="text-muted">
{days} дн.
</span>
);
@@ -495,7 +500,7 @@ function BillingManager() {
<div className="card">
<div className="card-body py-3">
<div className="d-flex align-items-center">
<span className="avatar avatar-md me-3 bg-primary-lt text-primary border-0">
<span className="avatar avatar-md me-3 bg-blue-lt text-blue border-0">
<IconCurrencyDollar size={24} />
</span>
<div>
@@ -512,7 +517,7 @@ function BillingManager() {
<div className="card">
<div className="card-body py-3">
<div className="d-flex align-items-center">
<span className={`avatar avatar-md me-3 ${overduePayments.length > 0 ? 'bg-danger-lt text-danger' : 'bg-success-lt text-success'} border-0`}>
<span className={`avatar avatar-md me-3 ${overduePayments.length > 0 ? 'bg-red-lt text-red' : 'bg-green-lt text-green'} border-0`}>
<IconAlertTriangle size={24} />
</span>
<div>
@@ -529,7 +534,7 @@ function BillingManager() {
<div className="card">
<div className="card-body py-3">
<div className="d-flex align-items-center">
<span className={`avatar avatar-md me-3 ${urgentPayments.length > 0 ? 'bg-warning-lt text-warning' : 'bg-blue-lt text-blue'} border-0`}>
<span className={`avatar avatar-md me-3 ${urgentPayments.length > 0 ? 'bg-yellow-lt text-yellow' : 'bg-azure-lt text-azure'} border-0`}>
<IconClock size={24} />
</span>
<div>
@@ -568,21 +573,21 @@ function BillingManager() {
</div>
{/* Быстрые фильтры */}
<div className="btn-group btn-group-sm">
<div className="d-flex gap-1">
<button
className={`btn ${filterUrgency === '' ? 'btn-primary' : 'btn-outline-primary'}`}
className={`btn btn-sm ${filterUrgency === '' ? 'btn-primary' : 'btn-outline-secondary'}`}
onClick={() => { setFilterUrgency(''); setCurrentPage(1); }}
>
Все
</button>
<button
className={`btn ${filterUrgency === 'overdue' ? 'btn-danger' : 'btn-outline-danger'}`}
className={`btn btn-sm ${filterUrgency === 'overdue' ? 'btn-red' : 'btn-outline-secondary'}`}
onClick={() => { setFilterUrgency('overdue'); setCurrentPage(1); }}
>
Просрочено
</button>
<button
className={`btn ${filterUrgency === 'urgent' ? 'btn-warning' : 'btn-outline-warning'}`}
className={`btn btn-sm ${filterUrgency === 'urgent' ? 'btn-yellow' : 'btn-outline-secondary'}`}
onClick={() => { setFilterUrgency('urgent'); setCurrentPage(1); }}
>
Срочно
@@ -694,14 +699,16 @@ function BillingManager() {
<UrgencyBadge days={days} />
</td>
<td className="text-center">
<span className={`badge ${item.status === 'active' ? 'bg-success-lt text-success' : 'bg-secondary-lt text-secondary'}`}>
{item.status === 'active' ? '●' : '○'}
</span>
{item.status === 'active' ? (
<span className="badge bg-green-lt text-green">Активен</span>
) : (
<span className="badge bg-secondary-lt text-secondary">Неактивен</span>
)}
</td>
<td>
<div className="btn-list gap-1 justify-content-end">
<div className="btn-list gap-1 justify-content-end flex-nowrap">
<button
className="btn btn-ghost-success btn-icon btn-sm"
className="btn btn-icon btn-sm btn-outline-success"
onClick={() => {
setPaymentDraft({
serverId: item.id,
@@ -717,14 +724,14 @@ function BillingManager() {
<IconCreditCard size={16} />
</button>
<button
className="btn btn-ghost-primary btn-icon btn-sm"
className="btn btn-icon btn-sm btn-outline-primary"
onClick={() => handleEditItem(item)}
title="Редактировать"
>
<IconEdit size={16} />
</button>
<button
className="btn btn-ghost-danger btn-icon btn-sm"
className="btn btn-icon btn-sm btn-outline-danger"
onClick={() => handleDeleteItem(item)}
title="Удалить"
>
@@ -830,9 +837,9 @@ function BillingManager() {
</td>
<td className="text-muted small">{r.note || '—'}</td>
<td>
<div className="btn-list gap-1 justify-content-end">
<div className="btn-list gap-1 justify-content-end flex-nowrap">
<button
className="btn btn-ghost-primary btn-icon btn-sm"
className="btn btn-icon btn-sm btn-outline-secondary"
onClick={() => {
setPaymentDraft({
serverId: r.server.id,
@@ -849,7 +856,7 @@ function BillingManager() {
<IconEdit size={14} />
</button>
<button
className="btn btn-ghost-danger btn-icon btn-sm"
className="btn btn-icon btn-sm btn-outline-danger"
onClick={() => {
setPaymentToDelete({ serverId: r.server.id, index: r._index, data: r });
setShowDeletePaymentModal(true);
@@ -1077,21 +1084,35 @@ function BillingForm({ item, onItemChange, servers }) {
<div className="col-12">
<div className="form-label">Статус</div>
<div className="btn-group w-100">
<button
type="button"
className={`btn ${item.status === 'active' ? 'btn-success' : 'btn-outline-success'}`}
onClick={() => onItemChange({ ...item, status: 'active' })}
>
Активен
</button>
<button
type="button"
className={`btn ${item.status === 'inactive' ? 'btn-secondary' : 'btn-outline-secondary'}`}
onClick={() => onItemChange({ ...item, status: 'inactive' })}
>
Неактивен
</button>
<div className="d-flex gap-2">
<label className="form-selectgroup-item flex-fill">
<input
type="radio"
name="status"
value="active"
className="form-selectgroup-input"
checked={item.status === 'active'}
onChange={() => onItemChange({ ...item, status: 'active' })}
/>
<span className="form-selectgroup-label">
<IconCheck size={16} className="me-1" />
Активен
</span>
</label>
<label className="form-selectgroup-item flex-fill">
<input
type="radio"
name="status"
value="inactive"
className="form-selectgroup-input"
checked={item.status === 'inactive'}
onChange={() => onItemChange({ ...item, status: 'inactive' })}
/>
<span className="form-selectgroup-label">
<IconX size={16} className="me-1" />
Неактивен
</span>
</label>
</div>
</div>