From f3f882b632744915be06b3f9a746cd50a7d44dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Falco=CC=81n?= Date: Mon, 29 Jun 2026 18:07:41 +0200 Subject: [PATCH] feat(ai): mark correction-learned rules with the AI icon in settings Rules with origin `correction` are AI-derived (learned from a user's correction of an AI categorization), so they now carry the same AI sparkle as `ai` rules in settings > automation rules, with a tooltip that names their actual source ("Learned from your correction"). --- lang/es.json | 1 + .../automation-rule-title.test.tsx | 12 ++++++++++++ .../automation-rules/automation-rule-title.tsx | 14 +++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lang/es.json b/lang/es.json index 7a8460fd..f72af901 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1,5 +1,6 @@ { "Learned: similar transactions will be categorized automatically.": "Aprendido: las transacciones similares se categorizarán automáticamente.", + "Learned from your correction": "Aprendida de tu corrección", "Undo": "Deshacer", "This subscription is no longer eligible for a self-service refund.": "Esta suscripción ya no es elegible para una devolución automática.", "Your payment was refunded, your subscription was canceled, and your bank connections were disconnected.": "Te hemos devuelto el pago, cancelado la suscripción y desconectado tus cuentas bancarias.", diff --git a/resources/js/components/automation-rules/automation-rule-title.test.tsx b/resources/js/components/automation-rules/automation-rule-title.test.tsx index ecd2fdf5..dc0d0b81 100644 --- a/resources/js/components/automation-rules/automation-rule-title.test.tsx +++ b/resources/js/components/automation-rules/automation-rule-title.test.tsx @@ -30,6 +30,15 @@ describe('AutomationRuleTitle', () => { expect(screen.getByLabelText('Created by AI')).toBeInTheDocument(); }); + it('prefixes the title with the AI sparkle when the rule was learned from a correction', () => { + render(); + + expect(screen.getByText('Supermarket')).toBeInTheDocument(); + expect( + screen.getByLabelText('Learned from your correction'), + ).toBeInTheDocument(); + }); + it('shows no marker for user-created rules', () => { render(); @@ -37,5 +46,8 @@ describe('AutomationRuleTitle', () => { expect( screen.queryByLabelText('Created by AI'), ).not.toBeInTheDocument(); + expect( + screen.queryByLabelText('Learned from your correction'), + ).not.toBeInTheDocument(); }); }); diff --git a/resources/js/components/automation-rules/automation-rule-title.tsx b/resources/js/components/automation-rules/automation-rule-title.tsx index 9cf72261..c6a5559e 100644 --- a/resources/js/components/automation-rules/automation-rule-title.tsx +++ b/resources/js/components/automation-rules/automation-rule-title.tsx @@ -9,16 +9,20 @@ import { type AutomationRule } from '@/types/automation-rule'; import { __ } from '@/utils/i18n'; /** - * A rule's title, prefixed with the shared AI sparkle when the rule itself was - * generated by AI (origin === 'ai'). + * A rule's title, prefixed with the shared AI sparkle when the rule came from AI + * — either generated by auto-categorization (origin === 'ai') or learned from a + * user's correction of an AI categorization (origin === 'correction'). */ export function AutomationRuleTitle({ rule }: { rule: AutomationRule }) { - const isAiGenerated = rule.origin === 'ai'; - const label = __('Created by AI'); + const isAiRelated = rule.origin === 'ai' || rule.origin === 'correction'; + const label = + rule.origin === 'correction' + ? __('Learned from your correction') + : __('Created by AI'); return (
- {isAiGenerated && ( + {isAiRelated && (