feat: Add FAB with asset price update, mobile optimizations, and localized financial trend

- Add Floating Action Button (FAB) with 3 quick actions
- Implement Asset Price Update dialog for bulk price updates
- Add bulk price update API endpoint with transaction support
- Optimize multiselect, calendar, and dropdown options for mobile (44px touch targets)
- Add custom date range popover to save space in Overview header
- Localize number format suffixes (k/m/b for EN, rb/jt/m for ID)
- Localize date format in Financial Trend (Oct 8 vs 8 Okt)
- Fix negative values in trend line chart (domain auto)
- Improve Asset Price Update dialog layout (compact horizontal)
- Add mobile-optimized calendar with responsive cells
- Fix FAB overlay and close button position
- Add translations for FAB and asset price updates
This commit is contained in:
dwindown
2025-10-12 23:30:54 +07:00
parent 46488a09e2
commit 49d60676d0
33 changed files with 1340 additions and 444 deletions

View File

@@ -2,18 +2,17 @@ export const en = {
common: {
search: 'Search',
filter: 'Filter',
clearAll: 'Clear All',
add: 'Add',
edit: 'Edit',
delete: 'Delete',
cancel: 'Cancel',
save: 'Save',
delete: 'Delete',
edit: 'Edit',
add: 'Add',
close: 'Close',
loading: 'Loading...',
noData: 'No data',
confirm: 'Confirm',
loading: 'Loading...',
noData: 'No data available',
error: 'An error occurred',
success: 'Success',
error: 'Error',
total: 'Total',
date: 'Date',
amount: 'Amount',
@@ -28,6 +27,12 @@ export const en = {
showFilters: 'Show Filters',
hideFilters: 'Hide Filters',
},
numberFormat: {
thousand: 'k',
million: 'm',
billion: 'b',
},
nav: {
overview: 'Overview',
@@ -44,6 +49,7 @@ export const en = {
overviewPeriodPlaceholder: 'Select period',
customStartDatePlaceholder: 'Pick start date',
customEndDatePlaceholder: 'Pick end date',
selectDateRange: 'Select date range',
totalBalance: 'Total Balance',
totalIncome: 'Total Income',
totalExpense: 'Total Expense',
@@ -200,9 +206,11 @@ export const en = {
expense: 'Expense',
category: 'Category',
categoryPlaceholder: 'Select or type new category',
selectCategory: 'Select or type new category',
addCategory: 'Add',
memo: 'Memo (Optional)',
memoPlaceholder: 'Add a note...',
addMemo: 'Add a note...',
date: 'Date',
selectDate: 'Select date',
addSuccess: 'Transaction added successfully',
@@ -227,16 +235,25 @@ export const en = {
save: 'Save',
update: 'Update',
cancel: 'Cancel',
nameSaved: 'Name saved successfully',
nameError: 'Name cannot be empty',
nameSuccess: 'Name updated successfully',
nameLoading: 'Updating name...',
nameLoadingError: 'Failed to update name',
email: 'Email',
emailVerified: 'Email Verified',
emailNotVerified: 'Email Not Verified',
emailCannotBeChanged: 'Email cannot be changed',
avatar: 'Avatar',
changeAvatar: 'Change Avatar',
uploadAvatar: 'Upload Avatar',
avatarSynced: 'Avatar is synced from your Google account',
clickUploadAvatar: 'Click the upload button to change your avatar',
uploading: 'Uploading...',
avatarSuccess: 'Avatar updated successfully',
avatarError: 'Failed to update avatar',
security: 'Security',
password: 'Password',
@@ -252,6 +269,10 @@ export const en = {
updating: 'Updating...',
setPassword: 'Set Password',
updatePassword: 'Update Password',
passwordSetSuccess: 'Password set successfully',
passwordChangeSuccess: 'Password changed successfully',
passwordError: 'Failed to set password',
enterPassword: 'Please enter your password',
twoFactor: 'Two-Factor Authentication',
twoFactorDesc: 'Add an extra layer of security to your account',
@@ -259,12 +280,20 @@ export const en = {
phoneNumberPlaceholder: '+62812345678',
updatePhone: 'Update Phone',
phoneNumberDescription: 'Required for WhatsApp OTP verification',
phoneInvalid: 'Invalid phone number',
phoneNotRegistered: 'This number is not registered on WhatsApp. Please try another number.',
phoneSuccess: 'Phone number updated successfully',
phoneError: 'Failed to update phone number',
emailOtp: 'Email OTP',
emailOtpDesc: 'Receive verification codes via email',
enableEmailOtp: 'Enable Email OTP',
disableEmailOtp: 'Disable Email OTP',
checkYourEmailForTheVerificationCode: 'Check your email for the verification code',
emailOtpSent: 'OTP code has been sent to your email',
emailOtpEnabled: 'Email OTP enabled successfully',
emailOtpDisabled: 'Email OTP disabled successfully',
emailOtpError: 'Failed to send OTP code',
enable: 'Enable',
disable: 'Disable',
enabled: 'Enabled',
@@ -280,6 +309,10 @@ export const en = {
pleaseAddYourPhoneNumberInTheEditProfileTabFirst: 'Please add your phone number in the Edit Profile tab first',
checkYourWhatsAppForTheVerificationCodeOrCheckConsoleInTestMode: 'Check your WhatsApp for the verification code',
enterVerificationCode: 'Enter 6 digit code',
whatsappOtpSent: 'OTP code has been sent to WhatsApp',
whatsappOtpEnabled: 'WhatsApp OTP enabled successfully',
whatsappOtpDisabled: 'WhatsApp OTP disabled successfully',
whatsappOtpError: 'Failed to send OTP code',
authenticatorApp: 'Authenticator App',
authenticatorDesc: 'Use an authenticator app like Google Authenticator',
@@ -290,6 +323,9 @@ export const en = {
setupSecretKey: 'Secret Key (if you can\'t scan QR code):',
enableAuthenticatorApp: 'Enable Authenticator App',
disableAuthenticatorApp: 'Disable Authenticator App',
totpEnabled: 'Authenticator App enabled successfully',
totpDisabled: 'Authenticator App disabled successfully',
totpError: 'Failed to enable Authenticator App',
scanQr: 'Scan QR Code',
scanQrDesc: 'Scan this QR code with your authenticator app',
manualEntry: 'Or enter this code manually:',
@@ -302,8 +338,11 @@ export const en = {
deletePasswordRequired: 'You must set a password first before you can delete your account. Go to "Set Password" above.',
deleteAccountConfirm: 'Are you sure you want to delete your account? All data will be permanently lost.',
enterPasswordToDelete: 'Enter your password to confirm',
enterPasswordToDeletePlaceholder: 'Enter your password',
deleting: 'Deleting...',
yesDeleteMyAccount: 'Yes, Delete My Account',
deleteSuccess: 'Account deleted successfully',
deleteError: 'Failed to delete account',
},
dateRange: {
@@ -313,7 +352,30 @@ export const en = {
lastMonth: 'Last month',
thisYear: 'This year',
custom: 'Custom',
from: 'From',
to: 'To',
from: 'Start Date',
to: 'End Date',
},
fab: {
updateAssetPrices: 'Update Asset Prices',
quickTransaction: 'Quick Transaction',
quickWallet: 'Quick Wallet',
},
assetPriceUpdate: {
title: 'Update Asset Prices',
description: 'Update the price per unit for your asset wallets',
noAssets: 'You don\'t have any asset wallets yet. Create an asset wallet first.',
noChanges: 'No price changes detected',
pricePerUnit: 'Price per {unit}',
currentPrice: 'Current price',
lastUpdated: 'Last updated',
justNow: 'Just now',
minutesAgo: '{minutes} minutes ago',
hoursAgo: '{hours} hours ago',
daysAgo: '{days} days ago',
updateAll: 'Update All',
updateSuccess: '{count} asset price(s) updated successfully',
updateError: 'Failed to update asset prices',
},
}