Commit Graph

269 Commits

Author SHA1 Message Date
Víctor Falcón 1db8aa4643 ui(fix): use amount display for chart current balance 2025-12-25 12:15:35 +00:00
Víctor Falcón e84929d746 ui(fix): responsive design on account show page 2025-12-25 12:11:43 +00:00
Víctor Falcón 6e2ea65757 ui(fix): disable svg focus outline 2025-12-25 11:45:30 +00:00
Víctor Falcón a454d7ec25 Disable recharts outline 2025-12-24 17:51:48 +00:00
Víctor Falcón 70d6afec53 ui(fix): transaction filters on small screens 2025-12-24 12:52:20 +00:00
Víctor Falcón 9ac46a37e0 Add retry mechanism to email mailables and update supervisor config 2025-12-18 15:38:04 +01:00
Víctor Falcón 3eaa46fa27 feat(queue): Implement queueable email jobs with rate limiting 2025-12-18 12:54:05 +01:00
Víctor Falcón fb5c09dcd8 fix: use markdown to send user lead invitation mail 2025-12-18 12:12:31 +01:00
Víctor Falcón eb6d3ce091 welcome-page: explain e2e encryption 2025-12-18 09:33:34 +01:00
Víctor Falcón 7abc86218c command: send email to leads 2025-12-18 09:14:04 +01:00
Víctor Falcón c99812ae70 welcome-page: remove lead form 2025-12-18 08:49:15 +01:00
Víctor Falcón 10821e6679 Reapply "swap horizon -> queue:work on mysql"
This reverts commit 43d615869c.
2025-12-17 18:00:32 +01:00
Víctor Falcón 4a9f74d1b1 add best value to yearly price 2025-12-17 17:36:56 +01:00
Víctor Falcón 8f1f8dd405 fix: rong schedule import 2025-12-17 17:09:01 +01:00
Víctor Falcón f94110c83a pint 2025-12-17 17:08:02 +01:00
Víctor Falcón 9f5dedc8b9 horizon: notify admin is env var is set 2025-12-17 17:02:21 +01:00
Víctor Falcón d5d3c1ef1b horizon: takes snapshot every 5 min 2025-12-17 17:02:05 +01:00
Víctor Falcón 43d615869c Revert "swap horizon -> queue:work on mysql"
This reverts commit 214ad684a8.
2025-12-17 16:31:48 +01:00
Víctor Falcón 214ad684a8 swap horizon -> queue:work on mysql 2025-12-17 16:24:38 +01:00
Víctor Falcón 67347c36ed mail: whisper money logo on header 2025-12-17 15:29:55 +01:00
Víctor Falcón 35d91a3b13 chore(commands): unify command signatures 2025-12-17 12:36:57 +01:00
Víctor Falcón bbbe8e31bf command: delete user 2025-12-17 12:33:18 +01:00
Víctor Falcón 08f5d1f947 Test mail drip command 2025-12-17 12:23:32 +01:00
Víctor Falcón 2f6ee33d4d mails: header email 2025-12-17 12:08:36 +01:00
Víctor Falcón dbe9b8956f production: remove redis config 2025-12-17 11:53:28 +01:00
Víctor Falcón f36ddb4f36 Event listeners are autowired 2025-12-17 09:46:44 +01:00
Víctor Falcón 9cb063e515 Horizon: remove basic auth, add allowed emails list to env 2025-12-17 09:10:15 +01:00
Víctor Falcón 73bb25ae8f
feat: Implement drip email campaign system (#35)
## Summary

- Implement event-driven drip email campaign system for new user signups
- Add 5 targeted emails based on user journey (welcome, onboarding
reminder, promo code, import help, feedback)
- Configure Laravel Horizon with Redis queue for reliable job processing
- Track sent emails in `user_mail_logs` table to prevent duplicates

## Email Schedule

| Email | Timing | Condition |
|-------|--------|-----------|
| Welcome | 30 min after signup | All users |
| Onboarding Reminder | 1 day after signup | Not onboarded |
| Promo Code (FOUNDER) | 1 day after signup | Onboarded + has
transactions + not subscribed |
| Import Help | 1 day after signup | Onboarded + no transactions + not
subscribed |
| Feedback | 5 days after signup | Not subscribed |

## Architecture

```
User Registers → ScheduleDripEmailsListener
    ├─> SendWelcomeEmailJob (30 min delay)
    ├─> SendOnboardingReminderEmailJob (1 day delay)
    ├─> SendPromoCodeEmailJob (1 day delay)
    ├─> SendImportHelpEmailJob (1 day delay)
    └─> SendFeedbackEmailJob (5 days delay)
```

Each job checks conditions at execution time and either sends the email
+ logs it, or silently completes.

## Test plan

- [x] All 23 drip email tests pass
- [x] Migration creates `user_mail_logs` table
- [x] Jobs dispatch with correct delays
- [x] Emails only sent when conditions are met
- [x] Duplicate emails prevented via UserMailLog check
- [ ] Verify Horizon processes jobs in production
2025-12-17 08:34:17 +01:00
Víctor Falcón 54833fcdc0
feat: Configure Resend email integration (#34)
- Install symfony/resend-mailer package for Resend support
- Add RESEND_API_KEY to .env.example with documentation
- Create mail:test command to verify email configuration
- Users can now set MAIL_MAILER=resend in .env to use Resend
- Test command usage: php artisan mail:test email@example.com

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 14:57:19 +01:00
Víctor Falcón d6ec9ff290 new onboarding funnel id 2025-12-16 13:39:47 +01:00
Víctor Falcón 4b88146383 funnel: transaction import wizard 2025-12-16 13:30:04 +01:00
Víctor Falcón 890593d967 fix: automated rules broken and now they work in batches 2025-12-16 12:01:38 +01:00
Víctor Falcón c3b1a8df4c Laravel boost: add instructions for claude 2025-12-16 11:53:38 +01:00
Víctor Falcón 2c223dfb65 Importing transactions: action notification to categorize them 2025-12-16 11:41:42 +01:00
Víctor Falcón 716e21b219 fix: toast on mobile 2025-12-16 11:31:02 +01:00
Víctor Falcón f8bea791e8
Bulk actions/select all (#33) 2025-12-15 17:59:58 +01:00
Víctor Falcón 045c7a5752 fix: bulk action bar style 2025-12-15 14:43:45 +01:00
Víctor Falcón c9e08766c1 Update automated rule timestamp when adding/removing a category or label 2025-12-15 14:30:35 +01:00
Víctor Falcón bf0c9ae989
fix: Automated rules with labels (#32) 2025-12-15 13:42:12 +01:00
Víctor Falcón bf69d4fd3b
Onboarding fix (#31) 2025-12-15 12:44:29 +01:00
Víctor Falcón fe5a55b1be
Automated rules labels (#30)
![Uploading image.png…]()
2025-12-15 12:11:55 +01:00
Víctor Falcón 4c26c7588d
Amount display format (#29) 2025-12-15 10:44:13 +01:00
Víctor Falcón ab61266955 Fix amount field formatting when pressing Enter
- Add onKeyDown handler to AmountInput component to format value when Enter is pressed
- Ensure amount is properly parsed before form submission regardless of submission method
- Add browser test to verify amount formatting on Enter key press
2025-12-15 08:47:11 +01:00
Víctor Falcón e813849e7b fix: app logo icon auto of the dashboard 2025-12-14 17:11:34 +01:00
Víctor Falcón 3bf734f5e7 Min width for account column 2025-12-14 17:03:03 +01:00
Víctor Falcón 8811afbad8
feat: Add privacy mode to hide monetary amounts (#28)
## Summary
This PR implements a global privacy mode feature that allows users to
hide all monetary amounts throughout the application.

## Changes
- **Created PrivacyModeContext**: New context provider with localStorage
persistence for privacy mode state
- **Created AmountDisplay component**: Centralized component for
displaying monetary amounts with blur effect when privacy mode is
enabled
- **Updated app logo logic**: Logo now shows birdhouse icon when privacy
mode is enabled or encryption key is not set
- **Added privacy mode toggle**: New toggle in user menu to
enable/disable privacy mode
- **Replaced inline amount formatting**: All monetary amounts now use
the AmountDisplay component
- **Updated trend indicators**: AmountTrendIndicator and
PercentageTrendIndicator now use AmountDisplay
- **Added animated transitions**: Smooth transitions when toggling
privacy mode

## Features
- Privacy mode state persists across sessions (localStorage)
- Amounts display as `$•••.••` with blur effect when privacy mode is
enabled
- Animated transitions (300ms) when toggling privacy mode
- App logo changes to birdhouse when privacy mode is on
- Toggle accessible from user menu at the top

## Testing
- Tested privacy mode toggle functionality
- Verified amounts are hidden/shown correctly across all pages
- Confirmed logo animation works properly
- Verified localStorage persistence

## Screenshots
Privacy mode can be toggled from the user menu, and all amounts
throughout the application will be hidden with a blur effect.
2025-12-14 16:03:02 +01:00
Víctor Falcón ce09f32a92 fix: transaction list on account page 2025-12-14 13:37:03 +01:00
Víctor Falcón 4f380af8f8
Refactor: Transaction Table Layout and Styling Improvements (#26)
## Overview
This PR refactors the transaction table to improve layout, styling, and
user experience. The changes include better column organization,
improved date grouping, and enhanced visual consistency.

<img width="1302" height="595" alt="image"
src="https://github.com/user-attachments/assets/72dd38fa-bfa3-432c-a342-fbcc1a05414b"
/>

## Changes

### Layout & Structure
- Added date and account columns to the transaction table
- Consolidated description cell for better readability
- Improved date grouping functionality
- Enhanced transaction column definitions and organization

### Styling Improvements
- Improved column styling and cell padding throughout the table
- Updated bulk actions bar styling
- Adjusted account selector alignment
- Enhanced data-table component with better spacing and visual hierarchy

### Components Updated
- `transaction-columns.tsx` - Refactored column definitions
- `transaction-list.tsx` - Improved list rendering and layout
- `date-header.tsx` - New component for date grouping
- `data-table.tsx` - Enhanced table component styling
- `category-cell.tsx` - Improved category display
- `bulk-actions-bar.tsx` - Updated styling
- `transactions/index.tsx` - Updated page layout

## Files Changed
- 9 files changed
- 463 insertions(+), 182 deletions(-)

## Testing
- [x] Verify transaction table displays correctly
- [x] Check date grouping functionality
- [x] Test bulk actions bar alignment
- [x] Verify responsive behavior
2025-12-14 12:56:05 +01:00
Víctor Falcón 8e1b2c0969
Add sync now button to pending operations dialog (#27)
Adds a 'Sync now' button below the pending operations list in the
dialog, allowing users to manually trigger a sync directly from the
dialog.

## Changes
- Added new props to `PendingOperationsDialog`: `onSyncNow`,
`syncStatus`, and `isOnline`
- Added a button at the bottom of the dialog that triggers the sync
process
- Button shows loading state with spinning icon while syncing
- Button is disabled when offline or when sync is already in progress
2025-12-14 12:50:00 +01:00
Víctor Falcón 4b5d65ba03
feat: add transaction labels feature (#24)
## Summary

Add a labeling system for transactions that differs from categories in
that labels are ephemeral and created on-the-fly when assigned (no
pre-creation required). A transaction can have multiple labels
(many-to-many relationship), and labels can be used for filtering in the
transaction table and as actions in automation rules.

<img width="1372" height="484" alt="image"
src="https://github.com/user-attachments/assets/fd342b11-dafb-44ed-b818-578e1ea856e6"
/>
<img width="1373" height="613" alt="image"
src="https://github.com/user-attachments/assets/aa5cfb8b-50b7-4101-a872-54904924f234"
/>
<img width="1035" height="594" alt="image"
src="https://github.com/user-attachments/assets/ffa946b2-b01f-496b-8cb8-ab55ab5b79ed"
/>


## Changes

### Backend (Laravel)

- Add `labels` table with user_id, name, color, and soft deletes
- Add `label_transaction` pivot table for transaction-label many-to-many
- Add `automation_rule_labels` pivot table for automation rule-label
many-to-many
- Create Label model with relationships to User, Transaction, and
AutomationRule
- Add LabelController for CRUD operations (returns JSON for on-the-fly
creation)
- Add LabelSyncController for frontend sync
- Add LabelPolicy for authorization
- Update TransactionController to handle bulk label updates
- Update AutomationRuleController to handle label actions
- Add validation for label_ids in transactions and automation rules

### Frontend (React/TypeScript)

- Add Label type and color utilities
- Add labels table to IndexedDB (Dexie version 6)
- Create label-sync service with findOrCreate functionality
- Create LabelCombobox component with multi-select and create-on-type
- Add labels column to transactions table
- Add labels filter to transaction filters
- Add bulk label assignment in bulk actions bar
- Add labels action in create automation rule dialog
- Update rule engine to include labels in evaluation results

## Testing

- 11 feature tests for label CRUD
- 3 tests for label sync
- All 241 feature tests pass

## Screenshots

N/A - UI changes can be reviewed in browser
2025-12-13 13:02:19 +01:00