diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6f9f35..bb7022d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,22 @@ O formato segue [Keep a Changelog](https://keepachangelog.com/pt-BR/).
Este projeto adota [Versionamento Semântico](https://semver.org/pt-BR/).
+## [1.43.4] - 2025-12-16
+
+### Improved
+- **Badges Padronizados** - Estilo translúcido consistente em todo o sistema
+ - Padrão global via CSS: `bg-{color}` → estilo `bg-opacity-25 text-{color}` automático
+ - Aparência moderna e uniforme: background translúcido + texto colorido
+ - Afetados: RecurringTransactions, Accounts, Categories, TransactionsByWeek, FinancialHealth, CostCenters
+ - Widgets: UpcomingWidget, OverdueWidget, CalendarWidget, OverpaymentsAnalysis
+ - Simplificação: remover classes redundantes dos JSX, CSS aplica estilo
+
+- **Botões de Ação Padronizados** - RecurringTransactions
+ - Estilo outline consistente: `btn-outline-{color}` em todas as abas
+ - Templates e Instâncias usam mesmo padrão visual
+ - Info (visualizar), Primary (executar), Success (editar), Warning (adiar), Danger (excluir)
+
+
## [1.43.3] - 2025-12-16
### Improved
diff --git a/VERSION b/VERSION
index 6564ab3..4aec498 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.43.3
+1.43.4
diff --git a/frontend/src/components/dashboard/CalendarWidget.jsx b/frontend/src/components/dashboard/CalendarWidget.jsx
index c9875da..01ac736 100644
--- a/frontend/src/components/dashboard/CalendarWidget.jsx
+++ b/frontend/src/components/dashboard/CalendarWidget.jsx
@@ -606,7 +606,7 @@ const CalendarWidget = () => {
{item.description}
{item.type === 'recurring' && (
-
+
#{item.occurrence_number}
)}
diff --git a/frontend/src/components/dashboard/OverpaymentsAnalysis.jsx b/frontend/src/components/dashboard/OverpaymentsAnalysis.jsx
index 440957f..4cc3adf 100644
--- a/frontend/src/components/dashboard/OverpaymentsAnalysis.jsx
+++ b/frontend/src/components/dashboard/OverpaymentsAnalysis.jsx
@@ -226,7 +226,7 @@ const OverpaymentsAnalysis = ({ data, loading, onTransactionClick }) => {
)}
{(!isMobile || isExpanded) && (
-
+
Total: {currency(totalOverpayment, 'BRL')}
@@ -322,7 +322,7 @@ const OverpaymentsAnalysis = ({ data, loading, onTransactionClick }) => {
{tx.description.length > 25 ? tx.description.substring(0, 25) + '...' : tx.description}
-
+
+{currency(tx.variance, 'BRL')}
@@ -404,7 +404,7 @@ const OverpaymentsAnalysis = ({ data, loading, onTransactionClick }) => {
{currency(tx.actual_amount, 'BRL')}
-
+
+{currency(tx.variance, 'BRL')}
diff --git a/frontend/src/components/dashboard/UpcomingWidget.jsx b/frontend/src/components/dashboard/UpcomingWidget.jsx
index 8f7e88d..096b85a 100644
--- a/frontend/src/components/dashboard/UpcomingWidget.jsx
+++ b/frontend/src/components/dashboard/UpcomingWidget.jsx
@@ -206,7 +206,7 @@ const UpcomingWidget = () => {
{item.account?.name || '-'}
{item.type === 'recurring' && (
-
+
#{item.occurrence_number}
)}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 29bf2f4..9cbddb8 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -2878,3 +2878,11 @@ a,
.category-dropdown-scroll::-webkit-scrollbar-thumb:hover {
background: rgba(100, 116, 139, 0.7);
}
+
+/* Badges padronizados - estilo outline */
+.badge.bg-primary { background-color: rgba(59, 130, 246, 0.25) !important; color: #3b82f6 !important; }
+.badge.bg-success { background-color: rgba(34, 197, 94, 0.25) !important; color: #22c55e !important; }
+.badge.bg-danger { background-color: rgba(239, 68, 68, 0.25) !important; color: #ef4444 !important; }
+.badge.bg-warning { background-color: rgba(234, 179, 8, 0.25) !important; color: #eab308 !important; }
+.badge.bg-info { background-color: rgba(14, 165, 233, 0.25) !important; color: #0ea5e9 !important; }
+.badge.bg-secondary { background-color: rgba(148, 163, 184, 0.25) !important; color: #94a3b8 !important; }
diff --git a/frontend/src/pages/Accounts.jsx b/frontend/src/pages/Accounts.jsx
index 39d2152..ad89142 100644
--- a/frontend/src/pages/Accounts.jsx
+++ b/frontend/src/pages/Accounts.jsx
@@ -508,9 +508,9 @@ const Accounts = () => {
{accountTypes[account.type] || account.type}
{account.is_active ? (
- {t('common.active')}
+ {t('common.active')}
) : (
- {t('common.inactive')}
+ {t('common.inactive')}
)}
= 0 ? 'text-success' : 'text-danger'}`} style={{ fontSize: '0.95rem' }}>
@@ -575,9 +575,9 @@ const Accounts = () => {
|
{account.is_active ? (
- {t('common.active')}
+ {t('common.active')}
) : (
- {t('common.inactive')}
+ {t('common.inactive')}
)}
|
@@ -664,15 +664,15 @@ const Accounts = () => {
{liability.status === 'active' ? (
-
+
{t('common.active')}
) : liability.status === 'paid_off' ? (
-
+
{t('liabilities.paid')}
) : (
-
+
{liability.status}
)}
@@ -783,11 +783,11 @@ const Accounts = () => {
|
{liability.status === 'active' ? (
- {t('common.active')}
+ {t('common.active')}
) : liability.status === 'paid_off' ? (
- {t('liabilities.paid')}
+ {t('liabilities.paid')}
) : (
- {liability.status}
+ {liability.status}
)}
|
diff --git a/frontend/src/pages/Categories.jsx b/frontend/src/pages/Categories.jsx
index 4d48367..966d329 100644
--- a/frontend/src/pages/Categories.jsx
+++ b/frontend/src/pages/Categories.jsx
@@ -306,9 +306,9 @@ const Categories = () => {
{/* Status */}
{category.is_active ? (
- {t('common.active')}
+ {t('common.active')}
) : (
- {t('common.inactive')}
+ {t('common.inactive')}
)}
@@ -759,7 +759,7 @@ const Categories = () => {
{item.description}
- {item.matched_keyword}
+ {item.matched_keyword}
|
{item.category_name} |
diff --git a/frontend/src/pages/CostCenters.jsx b/frontend/src/pages/CostCenters.jsx
index a49ba3a..8dfa8d1 100644
--- a/frontend/src/pages/CostCenters.jsx
+++ b/frontend/src/pages/CostCenters.jsx
@@ -345,9 +345,9 @@ const CostCenters = () => {
{/* Status */}
{item.is_active ? (
- {t('common.active')}
+ {t('common.active')}
) : (
- {t('common.inactive')}
+ {t('common.inactive')}
)}
diff --git a/frontend/src/pages/FinancialHealth.jsx b/frontend/src/pages/FinancialHealth.jsx
index f90a8ff..c41e321 100644
--- a/frontend/src/pages/FinancialHealth.jsx
+++ b/frontend/src/pages/FinancialHealth.jsx
@@ -847,7 +847,7 @@ const FinancialHealth = () => {
{t(`financialHealth.trend.${data.trends?.income_trend?.direction}`)}
-
+
{data.trends?.income_trend?.strength}%
diff --git a/frontend/src/pages/RecurringTransactions.jsx b/frontend/src/pages/RecurringTransactions.jsx
index 420d6d8..f60ac21 100644
--- a/frontend/src/pages/RecurringTransactions.jsx
+++ b/frontend/src/pages/RecurringTransactions.jsx
@@ -7,6 +7,9 @@ import { recurringService, accountService, categoryService } from '../services/a
const RecurringTransactions = () => {
const { t } = useTranslation();
+ // Mobile detection
+ const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
+
// State
const [templates, setTemplates] = useState([]);
const [pendingInstances, setPendingInstances] = useState([]);
@@ -80,6 +83,13 @@ const RecurringTransactions = () => {
loadData();
}, [loadData]);
+ // Mobile resize detection
+ useEffect(() => {
+ const handleResize = () => setIsMobile(window.innerWidth < 768);
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []);
+
// Toast helper
const showToast = (message, type = 'success') => {
setToast({ show: true, message, type });
@@ -314,7 +324,7 @@ const RecurringTransactions = () => {
>
{t('recurring.pendingInstances')}
- {pendingInstances.length}
+ {pendingInstances.length}
@@ -379,7 +389,88 @@ const RecurringTransactions = () => {
{t('recurring.noTemplates')}
+ ) : isMobile ? (
+ // Mobile: Cards Layout
+
+ {templates.map((template) => (
+
+
+ {/* Header: Nome + Status */}
+
+
+
+ {template.name}
+
+ {template.transaction_description && (
+
+ {template.transaction_description}
+
+ )}
+
+
+ {template.is_active ? t('common.active') : t('common.inactive')}
+
+
+
+ {/* Frequência + Tipo */}
+
+
+
+ {t(`recurring.frequencies.${template.frequency}`, template.frequency)}
+ {template.frequency_interval > 1 && ` (x${template.frequency_interval})`}
+
+
+ {t(`transactions.${template.type}`)}
+
+ {(template.pending_instances_count || 0) > 0 && (
+
+ {template.pending_instances_count} {t('recurring.pendingInstances')}
+
+ )}
+
+
+ {/* Valor + Ações */}
+
+
+ {formatCurrency(template.planned_amount)}
+
+
+
+
+
+
+
+
+
+
+ ))}
+
) : (
+ // Desktop: Table Layout
@@ -417,7 +508,7 @@ const RecurringTransactions = () => {
{formatCurrency(template.planned_amount)}
|
-
+
{template.pending_instances_count || 0}
|
@@ -479,7 +570,90 @@ const RecurringTransactions = () => {
{t('recurring.noPendingInstances')}
+ ) : isMobile ? (
+ // Mobile: Cards Layout
+
+ {pendingInstances.map((instance) => {
+ const days = Math.ceil((new Date(instance.due_date) - new Date()) / (1000 * 60 * 60 * 24));
+ const isOverdue = days < 0;
+ const isDueToday = days === 0;
+
+ return (
+
+
+ {/* Header: Template + Status */}
+
+
+
+ {instance.template?.name}
+
+
+ {instance.template?.account?.name} • #{instance.occurrence_number}
+
+
+
+ {t(`recurring.status.${instance.status}`)}
+
+
+
+ {/* Data de vencimento */}
+
+
+
+ {formatDate(instance.due_date)}
+ {instance.status === 'pending' && (
+
+ {isOverdue && `(${Math.abs(days)} ${t('recurring.daysOverdue')})`}
+ {isDueToday && `(${t('recurring.dueToday')})`}
+ {!isOverdue && !isDueToday && `(${days} ${t('recurring.daysUntilDue')})`}
+
+ )}
+
+
+
+ {/* Valor + Ações */}
+
+
+ {formatCurrency(instance.planned_amount)}
+
+
+
+
+
+
+
+
+
+
+ );
+ })}
+
) : (
+ // Desktop: Table Layout
diff --git a/frontend/src/pages/TransactionsByWeek.jsx b/frontend/src/pages/TransactionsByWeek.jsx
index e82f606..26fcdd8 100644
--- a/frontend/src/pages/TransactionsByWeek.jsx
+++ b/frontend/src/pages/TransactionsByWeek.jsx
@@ -1414,7 +1414,7 @@ export default function Transactions() {
{/* Account + Category */}
-
+
{transaction.account?.name}
@@ -2674,7 +2674,7 @@ export default function Transactions() {