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:
@@ -231,11 +231,11 @@ export function TransactionDialog({ open, onOpenChange, transaction, walletId: i
|
||||
</ResponsiveDialogDescription>
|
||||
</ResponsiveDialogHeader>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid gap-4 p-4 md:py-4 md:px-0">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="wallet">{t.transactionDialog.wallet}</Label>
|
||||
<Label htmlFor="wallet" className="text-base md:text-sm">{t.transactionDialog.wallet}</Label>
|
||||
<Select value={walletId} onValueChange={setWalletId}>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="h-11 md:h-9 text-base md:text-sm">
|
||||
<SelectValue placeholder={t.transactionDialog.selectWallet} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -250,22 +250,22 @@ export function TransactionDialog({ open, onOpenChange, transaction, walletId: i
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="amount">{t.transactionDialog.amount}</Label>
|
||||
<Label htmlFor="amount" className="text-base md:text-sm">{t.transactionDialog.amount}</Label>
|
||||
<Input
|
||||
id="amount"
|
||||
type="number"
|
||||
step="0.01"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
placeholder={t.transactionDialog.amountPlaceholder}
|
||||
required
|
||||
placeholder="0"
|
||||
className="h-11 md:h-9 text-base md:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="direction">{t.transactionDialog.direction}</Label>
|
||||
<Label htmlFor="direction" className="text-base md:text-sm">{t.transactionDialog.direction}</Label>
|
||||
<Select value={direction} onValueChange={(value: "in" | "out") => setDirection(value)}>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="h-11 md:h-9 text-base md:text-sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -277,31 +277,34 @@ export function TransactionDialog({ open, onOpenChange, transaction, walletId: i
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="date">{t.transactionDialog.date}</Label>
|
||||
<Label htmlFor="date" className="text-base md:text-sm">{t.transactionDialog.date}</Label>
|
||||
<DatePicker
|
||||
date={selectedDate}
|
||||
onDateChange={(date) => date && setSelectedDate(date)}
|
||||
placeholder={t.transactionDialog.selectDate}
|
||||
className="h-11 md:h-9 text-base md:text-sm w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="category">{t.transactionDialog.category}</Label>
|
||||
<Label htmlFor="category" className="text-base md:text-sm">{t.transactionDialog.category}</Label>
|
||||
<MultipleSelector
|
||||
options={categoryOptions}
|
||||
selected={categories}
|
||||
onChange={setCategories}
|
||||
placeholder={t.transactionDialog.categoryPlaceholder}
|
||||
placeholder={t.transactionDialog.selectCategory}
|
||||
className="min-h-[44px] md:min-h-[40px] text-base md:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="memo">{t.transactionDialog.memo}</Label>
|
||||
<Label htmlFor="memo" className="text-base md:text-sm">{t.transactionDialog.memo}</Label>
|
||||
<Input
|
||||
id="memo"
|
||||
value={memo}
|
||||
onChange={(e) => setMemo(e.target.value)}
|
||||
placeholder={t.transactionDialog.memoPlaceholder}
|
||||
placeholder={t.transactionDialog.addMemo}
|
||||
className="h-11 md:h-9 text-base md:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -312,10 +315,10 @@ export function TransactionDialog({ open, onOpenChange, transaction, walletId: i
|
||||
)}
|
||||
</div>
|
||||
<ResponsiveDialogFooter>
|
||||
<Button type="button" variant="outline" onClick={() => handleOpenChange(false)}>
|
||||
<Button type="button" variant="outline" onClick={() => handleOpenChange(false)} className="h-11 md:h-9 text-base md:text-sm">
|
||||
{t.common.cancel}
|
||||
</Button>
|
||||
<Button type="submit" disabled={loading}>
|
||||
<Button type="submit" disabled={loading} className="h-11 md:h-9 text-base md:text-sm">
|
||||
{loading ? t.common.loading : isEditing ? t.common.save : t.common.add}
|
||||
</Button>
|
||||
</ResponsiveDialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user