Align with the expense calculation refactor from upstream `spliit-app/spliit#462#523
Closed
carnach wants to merge 92 commits into
Closed
Align with the expense calculation refactor from upstream `spliit-app/spliit#462#523carnach wants to merge 92 commits into
carnach wants to merge 92 commits into
Conversation
Add comprehensive QR code functionality to improve group sharing and joining experience: - Add QR code generation with embedded logo for sharing groups - Display QR codes in share dialog with Spliit logo overlay - Support downloading QR codes as PNG images - Use high error correction level for reliable scanning - Add camera-based QR code scanner for joining groups - Enable mobile devices to scan QR codes directly - Toggle between URL input and QR scanning on mobile - Handle camera permissions and error states gracefully - Add new dependencies: - qrcode.react (^4.2.0) for QR code generation - html5-qrcode (^2.3.8) for camera-based scanning - Add translation keys for QR code UI elements - Share QR code dialog (title, description, download button) - Scanner mode toggle (URL mode vs QR mode) fix responsiveness of qr import button
Prerelease
Convert InputGroupInput and InputGroupTextarea to use React.forwardRef and proper HTML attribute types to fix type incompatibility with ref prop
Add controlled state to calculator popover to automatically close it when the user clicks the Apply button, improving UX by not requiring manual dismissal after applying the calculated amount
…#13) * Initial plan * Address review comments: fix security, accessibility, i18n, and Tailwind compatibility Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Add calculator translations for all supported languages Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Fix operator precedence bug and invalid Tailwind selectors Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* feat: Add Vercel development tooling, analytics, and comprehensive backup/restore system
Development Enhancements:
- Added `dev:vercel` script to package.json for local Vercel development environment
- Integrated Vercel Analytics for web traffic and performance monitoring
- Added Analytics component to root layout for automatic tracking
Backup/Restore System:
Implemented a complete group backup and restore system with intelligent version management:
Core Features:
- Full group data export as ZIP archive containing:
* Group metadata (name, currency, information)
* All participants with their details
* Complete expense records with notes, documents, and recurring expense links
* Activity log entries
* Export metadata with version and timestamp
Restore Operations:
- Three operation modes based on version comparison:
1. CREATE: Import backup as new group when group doesn't exist
2. UPDATE: Merge newer data from backup into existing group
3. ROLLBACK: Replace all current data with older backup version
Technical Implementation:
- Version comparison using latest expense/activity timestamps
- Transactional restore operations using Prisma for data integrity
- Detailed difference calculation (added/removed expenses and participants)
- ZIP format with backup.json and metadata.json files
- Type-safe implementation with comprehensive error handling
User Interface:
- Export dropdown menu with "Create Backup" option
- RestoreBackupButton component on groups page with DropdownMenu containing MoreVertical icon
- Make RestoreBackupButton dialog controllable via open/onOpenChange props
- Update translations to include restoreBackup key in Groups section- Interactive workflow with analysis, confirmation, and progress states
- Clear visual feedback for version comparison results
- Warning dialogs for destructive operations (rollback)
Files Added:
- src/app/groups/[groupId]/backup/export/route.ts (121 lines)
- src/app/groups/backup/import/route.ts (123 lines)
- src/lib/backup.ts (371 lines)
- src/components/restore-backup-button.tsx (313 lines)
Files Modified:
- package.json: Added dev:vercel script, @vercel/analytics, jszip dependencies
- src/app/layout.tsx: Integrated Analytics component
- src/app/groups/[groupId]/export-button.tsx: Added backup option to export dropdown
- src/app/groups/recent-group-list.tsx: Added restore backup button
- messages/en-US.json: Complete backup/restore translations (18 keys)
Dependencies Added:
- @vercel/analytics@1.6.1: Web analytics integration
- jszip@3.10.1: ZIP archive creation for backup packaging
- Replace standalone RestoreBackupButton with DropdownMenu containing MoreVertical icon
- Make RestoreBackupButton dialog controllable via open/onOpenChange props
- Add "Restore Backup" menu item to Groups page header dropdown
- Update translations to include restoreBackup key in Groups section
This provides a cleaner groups page header while maintaining easy access to backup restoration functionality.
* feat: add JSON import system for group migration with undo capability
- Add JSON import endpoint (src/app/groups/json/import/route.ts)
- Analyze existing vs new group data
- Restore/create groups in 60s transaction timeout
- Support create, update, and rollback modes with version comparison
- Add core import logic (src/lib/json-import.ts)
- Version comparison using expense dates
- Differential updates for incremental imports
- Participant ID validation before expense creation
- Activity tracking with import date metadata
- Add undo last import feature (src/app/groups/[groupId]/data/delete/route.ts)
- Remove all expenses/participants/activities created in last import
- Only available when JSON_IMPORT_START marker exists
- Add import marker detection (src/app/api/groups/[groupId]/has-import-marker/route.ts)
- Checks for JSON_IMPORT_START activity to show undo button
- Conditional rendering of delete options
- Add UI components
- ImportJSONButton: Dialog with analyze/restore/rollback workflow
- DeleteDataButton: Undo import only (conditional on import marker)
- Activity display: Shows 'Import (date)' for system-created entries
- Activity improvements
- JSON-embed import date and expense title in activity.data
- Set activity.time to importTime for consistency in undo logic
- Parse and display import date in activity list UI
- UX/localization
- Add JSONImport translations (23 keys)
- Update DeleteData translations (undo-only mode)
- Remove clear-all option from UI
- Add ImportJSONButton to recent groups menu
- Bug fixes
- Fixed null value warning in expense form (value={field.value ?? ''})
- Removed debug endpoints
- Removed console logging from import logic
Technical notes:
- Transaction timeout: 60s (from 5s default) for large imports
- Import activities timestamped at importTime for accurate undo
- Participant ID validation prevents orphaned expense data
- Version comparison uses latest expense date as proxy
- Differential updates merge with existing participants/expenses
* fix: use expense dates for activity timeline instead of import timestamp
- Revert activity entries to use their original expense dates for proper chronological display
- Keep import date in activity metadata shown in brackets after 'Import' label
- Applies to all import modes (create, update, rollback)
- Individual expenses now appear at their original dates while maintaining import timestamp reference
* refactor: move backup export to bottom of recent group menu
- Reorder menu items: Remove from Recent Groups, Archive Group, then Create Backup
- Places destructive action first, then export at the bottom
* feat: comprehensive group management and backup improvements
Features Added:
- Delete group functionality with permanent deletion warning dialog
- Optional S3 document deletion when deleting groups
- Document URL validation during backup restore
- Backup export moved from expenses dropdown to recent groups menu
- JSON import activity message clarified
Delete Group:
- Add 'Delete group permanently' option to recent groups three-dots menu
- Create confirmation dialog with backup recommendation
- Query and display S3 document count if present
- Warn that cloud images don't form part of backup
- Optional checkbox to delete S3 images when deleting group
- Implement deleteGroupWithDocuments API with S3Client integration
- Create TRPC procedures for delete and document count
Backup Restore Improvements:
- Check document URLs exist before restoring
- Skip missing documents and continue operation
- Collect and return warnings for unavailable resources
- Display warnings to user via alert dialog
- Update restoreGroupFromBackup signature to return warnings
UI/UX Improvements:
- Move 'Create Backup' from expenses export dropdown to groups menu
- Position at bottom of menu after Archive Group option
- Fix malformed JSON in en-US translations (RecentRemovedToast)
- Update JSON import message: 'Activity history is not preserved, it will be regenerated'
- Fix expense form indentation (formatting cleanup)
Technical Details:
- Add AWS SDK S3Client for document deletion
- Implement checkUrlExists helper using fetch HEAD requests
- Add getGroupDocumentCount API and TRPC procedure
- Update deleteGroup to deleteGroupWithDocuments with optional flag
- Handle missing S3 credentials gracefully
* fix: resolve S3 integration issues and improve deletion workflows
Architectural Improvements:
- Move S3 deletion logic to server actions (delete-group-actions.ts)
- Use 'use server' directive to safely handle env variables
- Prevent ZodError in client by keeping env imports server-side only
- Separate concerns: database operations in api.ts, S3 in server actions
S3 Document Management:
- Fix document ID preservation during expense creation (use doc.id instead of randomId())
- Add S3 cleanup when deleting individual expenses
- Add S3 cleanup when deleting groups with deleteDocuments flag
- Ensure ExpenseDocument table entries are deleted alongside S3 objects
- Implement helper function deleteS3DocumentsByUrls for reusability
Database Cleanup:
- Explicitly delete ExpenseDocument records before deleting expenses
- Explicitly delete ExpenseDocument records before deleting groups
- Prevent orphaned document references in database
- Use upsert for backup restore to handle duplicate documents gracefully
Backup/Restore:
- Fix duplicate document creation error during backup restore
- Use upsert instead of create to handle existing documents
- Maintain document-expense relationships properly during restore
Recent Groups UI:
- Reorder dropdown menu for better UX:
1. Create Backup
2. Archive Group
3. Remove from recent groups
4. Delete group permanently
- Add icons to all menu items (Archive, ArchiveX, X, Trash2)
- Remove deleted group from recent list automatically
- Refresh groups list after permanent deletion
TRPC Procedures:
- Update delete group procedure to call S3 server action
- Update delete expense procedure to call S3 server action
- Maintain proper order: S3 deletion → document cleanup → entity deletion
Technical Details:
- Server action: deleteGroupS3Documents(groupId)
- Server action: deleteExpenseS3Documents(expenseId)
- Helper: deleteS3DocumentsByUrls(urls[])
- Prevents client-side env variable access
- Maintains separation of concerns
- All deletions now properly cascade through S3 and database
* update package-lock
* update package-lock for node v20
* Address code review feedback: security, performance, and UX improvements (#15)
* Initial plan
* fix: address simple review comments - participant cleanup, file validation, S3 extraction
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* fix: improve error handling, logging, and internationalization
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* perf: optimize backup and JSON import with batch database operations
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* fix: improve undo import logic and replace alert with toast
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* fix: ensure categories exist before restoring expenses from backup
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* docs: add security notes about link-sharing authentication model
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* fix: use safe delimiter for category keys and remove unused variable
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* refactor: simplify prisma query and improve comments
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* refactor: extract category key helpers and remove sensitive data from logs
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* fix: add validation to category key parser and sanitize error logs
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* match prisma schema
* dded the downlevelIteration compiler option to tsconfig.json
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
Co-authored-by: carnach <gevert@gmail.com>
* post prettier
* fix merge issue
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
…#16) feat: Add anonymous auth with WebAuthn passkeys and rate limiting Implement anonymous users with username/passphrase recovery Add WebAuthn passkey registration/authentication Add group association sync and account management Add rate limiting and smart persistence Update schema, migrations, and documentation
* feat: Add anonymous user authentication with WebAuthn passkey support - Implement anonymous user system with UUID-based accounts - Add username/passphrase authentication with SHA-256 hashing - Add WebAuthn/passkey support for passwordless login - Implement passphrase complexity validation with visual indicators - Add group association management for anonymous users - Add account recovery via username + passphrase - Add change passphrase functionality for authenticated users - Add passkey management (generate/remove) for linked accounts - Add sign out vs delete account options with group cleanup choice - Implement IP-based rate limiting (10 req/min) on all endpoints - Add smart persistence (only save accounts with groups or auth) - Add password manager compatibility (1Password, etc.) - Create Prisma schema with AnonymousUser and AnonymousUserGroup models - Add three database migrations for user tables and passkey fields - Position anonymous auth menu in header navigation - Add ANONYMOUS_USER_CHANGES.md documentation Technical details: - Next.js 16 with Turbopack configuration - Prisma 6.18 with PostgreSQL (Neon) - @simplewebauthn/browser and @simplewebauthn/server v10.0.0 - localStorage for client-side auth state - Discoverable credentials for cross-device passkey login - Dynamic WebAuthn rpID/origin derivation for all environments - In-memory rate limiting with automatic cleanup * Fixed the TypeScript error. * Added proper type annotation for the parsed JSON body * correct types and include the transports from the database if available. * added a type assertion as string[] to the parsed JSON value. * Update the transports typing to AuthenticatorTransportFuture[] and imported the type to satisfy generateAuthenticationOptions * Remove the unavailable AuthenticatorTransportFuture type omitted transports from allowCredentials, which resolves the compile error while keeping the flow intact * Aligned outputFileTracingRoot with turbopack.root in next.config.mjs. Installed latest baseline-browser-mapping (package.json and package-lock.json updated * ype error in route.ts by typing the parsed request body before accessing userId and username * fix issues * Address code review feedback: error handling, validation, race conditions (#17) * Initial plan * Address code review comments - error handling, validation, and type fixes Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Add documentation, improve error messages, and enforce passphrase complexity Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Add security review notes documenting remaining architectural concerns Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Add environment variable validation in security documentation Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Fixed the error by selecting passkeyTransports in the query so it can be referenced. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> Co-authored-by: carnach <carnach@users.noreply.github.com> Co-authored-by: carnach <gevert@gmail.com> * fix: Replace deprecated @simplewebauthn/types with inline types - Remove @simplewebauthn/types imports (package no longer supported) - Use inline type definitions and any assertions for WebAuthn responses - Fix TypeScript compilation errors in passkey routes - Fix rate limit cleanup loop syntax error - Fix request body type assertions in API routes - Align outputFileTracingRoot with turbopack.root in next.config - Update baseline-browser-mapping to latest version - All builds now passing successfully * fix new user * fix: New account button now correctly creates account instead of attempting recovery - Remove form wrapper that was routing submit to recovery handler - Make 'New account' button explicitly call handleSavePassphrase - Prevents error when user tries to create new account with filled credentials --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
Add server-side session management with secure token generation and implement session-based authorization on all protected endpoints. Store WebAuthn challenges server-side to prevent replay attacks. Security fixes: - Prevent unauthorized account modifications - Prevent WebAuthn replay attacks - Add proper authorization checks on delete/update operations - Validate session ownership on all protected endpoints Resolves all critical security issues identified in security review.
Fix WebAuthn challenge handling to comply with spec while maintaining security: - Send challenge to client (required by WebAuthn specification) - Store challenge server-side in session for verification - Validate client challenge matches server challenge on verify - Use server challenge for cryptographic verification (prevents tampering) This maintains security while restoring passkey functionality: - Client cannot manipulate challenges (server validates match) - One-time use enforcement (challenge deleted after verification) - 5-minute TTL on challenges - Session required for all operations
…h associated groups Only show "Delete group permanently" and "Create Backup" options for users who: - Are logged in (anonymousLinked = true) - Have the group in their associated groups (anonymousAssociatedGroups) This prevents accidental or malicious deletion of groups by anonymous users who do not have explicit ownership of the group.
…roups When logging out and choosing to remove associated groups: - Explicitly call setRecentGroupsState([]) to update UI immediately - Send API request to clear groups from server - UI updates without needing manual refresh
Add database-backed session storage to fix session expiration on server restart - Create AnonymousSession table with token, userId, expiresAt, and challenge fields - Replace in-memory Map with Prisma queries in SessionStore - Sessions now persist across server restarts and deployments Fix group recovery and sign-out behavior - Fix naming conflict between setRecentGroups state setter and helper function - Groups now properly save to localStorage when logging in - Sign-out only clears localStorage, preserving groups in database for recovery - Groups restore automatically when logging back in with same account Improve UI for logged-in users - Move Restore from backup and Import from JSON to account dropdown menu - Hide restore/import options from groups page for logged-in users - Better organization of account management features Add server-side authorization to group deletion - Validate user session before allowing group deletion - Verify group ownership through anonymousUserGroup table - Return appropriate error codes (401 UNAUTHORIZED, 403 FORBIDDEN) - Prevents unauthorized deletion even if UI is bypassed
Add ability to register multiple passkeys per anonymous account with custom names - Create new Passkey table with name, credentialId, publicKey, counter, lastUsedAt fields - Migrate from single passkey storage on AnonymousUser to separate Passkey table - Add passkey name input dialog when registering new passkeys - Display list of all registered passkeys with creation dates - Add individual passkey deletion with confirmation dialog - Update lastUsedAt timestamp when passkey is used for authentication - Add /api/anonymous-users/passkey/list endpoint to fetch user's passkeys - Maintain backward compatibility with deprecated passkey fields on AnonymousUser UI improvements: - Show passkey list with name and creation date in account dialog - Add 'Add passkey' button that opens name input dialog - Individual remove button for each passkey - Better UX with 'New account' button highlighted when generating username - Changed 'Recover account' to 'Existing account' for clarity
- Change auth-options endpoint to fetch credentials from Passkey table - Support multiple passkeys by returning all credential IDs for allowCredentials - Fixes 'No passkey registered' error when authenticating
- Add upsert to create AnonymousUser if not exists before session creation - Prevents foreign key constraint violation in AnonymousSession table - Handle both authenticated and discoverable credential flows
…set flows - Always require current passphrase for normal passphrase change - Add separate reset flow for passkey-authenticated users - Reset with passkey only requires new passphrase (no current) - Add hasPassphrase flag to groups API response - Update UI to conditionally show options based on passphrase state - Add passkeyResetMode state to differentiate between change and reset - Server-side validation enforces security requirements
…nup optimization (#20) * Initial plan * Address code review comments: fix security and reliability issues Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Refactor: extract session retrieval helper and add temp user cleanup Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Improve error messages and add error logging for debugging Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Polish error message for clarity Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
* add anonymous account * feat: implement database-backed sessions and improve group management Add database-backed session storage to fix session expiration on server restart - Create AnonymousSession table with token, userId, expiresAt, and challenge fields - Replace in-memory Map with Prisma queries in SessionStore - Sessions now persist across server restarts and deployments Fix group recovery and sign-out behavior - Fix naming conflict between setRecentGroups state setter and helper function - Groups now properly save to localStorage when logging in - Sign-out only clears localStorage, preserving groups in database for recovery - Groups restore automatically when logging back in with same account Improve UI for logged-in users - Move Restore from backup and Import from JSON to account dropdown menu - Hide restore/import options from groups page for logged-in users - Better organization of account management features Add server-side authorization to group deletion - Validate user session before allowing group deletion - Verify group ownership through anonymousUserGroup table - Return appropriate error codes (401 UNAUTHORIZED, 403 FORBIDDEN) - Prevents unauthorized deletion even if UI is bypassed * update sigin UI * feat: support multiple passkeys per account with names Add ability to register multiple passkeys per anonymous account with custom names - Create new Passkey table with name, credentialId, publicKey, counter, lastUsedAt fields - Migrate from single passkey storage on AnonymousUser to separate Passkey table - Add passkey name input dialog when registering new passkeys - Display list of all registered passkeys with creation dates - Add individual passkey deletion with confirmation dialog - Update lastUsedAt timestamp when passkey is used for authentication - Add /api/anonymous-users/passkey/list endpoint to fetch user's passkeys - Maintain backward compatibility with deprecated passkey fields on AnonymousUser UI improvements: - Show passkey list with name and creation date in account dialog - Add 'Add passkey' button that opens name input dialog - Individual remove button for each passkey - Better UX with 'New account' button highlighted when generating username - Changed 'Recover account' to 'Existing account' for clarity * fix: update auth-options to use new Passkey table - Change auth-options endpoint to fetch credentials from Passkey table - Support multiple passkeys by returning all credential IDs for allowCredentials - Fixes 'No passkey registered' error when authenticating * fix: ensure user exists before creating passkey auth session - Add upsert to create AnonymousUser if not exists before session creation - Prevents foreign key constraint violation in AnonymousSession table - Handle both authenticated and discoverable credential flows * feat: enforce passphrase security requirements and separate change/reset flows - Always require current passphrase for normal passphrase change - Add separate reset flow for passkey-authenticated users - Reset with passkey only requires new passphrase (no current) - Add hasPassphrase flag to groups API response - Update UI to conditionally show options based on passphrase state - Add passkeyResetMode state to differentiate between change and reset - Server-side validation enforces security requirements * Address code review feedback: authorization, error handling, and cleanup optimization (#20) * Initial plan * Address code review comments: fix security and reliability issues Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Refactor: extract session retrieval helper and add temp user cleanup Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Improve error messages and add error logging for debugging Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> * Polish error message for clarity Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: carnach <26198260+carnach@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Mobile-friendly UI improvements fixes * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * add charts * fix home page content --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
update translations
Refine the group mobile navigation by keeping primary tabs visible and moving secondary sections into a More menu. Redesign expense rows with a clearer transaction layout, category affordance, and full-row navigation. Replace recent group button wrappers with proper clickable cards, separate management controls, and improved loading and empty states.
Replace heavier repeated card shells on group pages with lighter section headers and bordered content panels. Improve expense, activity, reimbursement, and chart loading or empty states with skeletons, icons, and clearer calls to action.
Reduce shadow-heavy card styling across the group app surfaces and rely more on borders and muted backgrounds for a cleaner interface. Polish recent group card focus treatment and normalize homepage feature card rounding. Keep the balances view on the preferred mirrored chart while removing extra shadow from its surrounding panels.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Use public/new logo.png as the source for Android, iOS, PWA, favicon, and Next app icon assets. Generate light and dark header wordmark images so the top banner remains readable in both themes. Archive the previous logo assets under public/logo-archive with restore instructions for easy rollback. Update the icon generation script to reproduce the new assets and emit RGBA favicon frames compatible with Next.
* Improve mobile navigation and list UI Refine the group mobile navigation by keeping primary tabs visible and moving secondary sections into a More menu. Redesign expense rows with a clearer transaction layout, category affordance, and full-row navigation. Replace recent group button wrappers with proper clickable cards, separate management controls, and improved loading and empty states. * Lighten group page sections and empty states Replace heavier repeated card shells on group pages with lighter section headers and bordered content panels. Improve expense, activity, reimbursement, and chart loading or empty states with skeletons, icons, and clearer calls to action. * Tighten app visual styling Reduce shadow-heavy card styling across the group app surfaces and rely more on borders and muted backgrounds for a cleaner interface. Polish recent group card focus treatment and normalize homepage feature card rounding. Keep the balances view on the preferred mirrored chart while removing extra shadow from its surrounding panels. * add calculator to custom expense split * clear group after deletion * disable delete function unless associated * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * update translations for new functionality --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…routes
- Remove target='_blank' from export-button.tsx internal routes (JSON/CSV export)
- Remove target='_blank' from recent-group-list-card.tsx backup export link
- Remove target='_blank' from delete-group-dialog.tsx backup export link
- Replace window.open('/help', '_blank') with router.push('/help') in new-features-dialog.tsx
On iOS PWA, attempting to open internal routes in new tabs triggers an overlay
prompting to cancel or open in external browser. These changes ensure all
internal navigation uses Next.js routing to stay within the PWA context.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Aligns this fork with the expense calculation refactor from upstream
spliit-app/spliit#462.This centralizes participant share calculation so totals, balances, CSV export, and the expense form preview all use the same rounding and remainder-distribution logic.
Changes
calculateShares()insrc/lib/totals.tscalculateShare()to delegate to the centralized share calculationdecimal.jsfor precise share calculation and deterministic minor-unit roundingpaidForcalculateShares()decimal.jsan explicit production dependencyValidation
npm test -- src/lib/totals.test.tsnpm run check-typesnpm run lintLint passes with existing warnings only.