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