Update TransactionsPage to match castle extension date range API changes
Synchronized TransactionsPage with castle LNbits extension API updates that introduced custom date range filtering. **API Changes (ExpensesAPI.ts):** - Updated `getUserTransactions()` to support `start_date` and `end_date` parameters (YYYY-MM-DD format) - Custom date range takes precedence over preset days parameter - Updated comment: default changed from 5 to 15 days, options now 15/30/60 (removed 5 and 90) **UI Changes (TransactionsPage.vue):** - **New defaults**: Changed default from 5 days to 15 days - **New preset options**: 15, 30, 60 days (removed 5 and 90 day options) - **Custom date range**: Added "Custom" option with date picker inputs - From/To date inputs using native HTML5 date picker - Apply button to load transactions for custom range - Auto-clears custom dates when switching back to preset days - **State management**: - `dateRangeType` ref supports both numbers (15, 30, 60) and 'custom' string - `customStartDate` and `customEndDate` refs for custom date range - **Smart loading**: Only loads transactions after user provides both dates and clicks Apply **Priority Logic:** - Custom date range (start_date + end_date) takes precedence - Falls back to preset days if custom not selected - Defaults to 15 days if custom selected but dates not provided Matches castle extension implementation exactly (see castle extension git diff in fava_client.py, views_api.py, and static/js/index.js). 🐢 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
509fae1d35
commit
84596e518e
2 changed files with 109 additions and 29 deletions
|
|
@ -404,7 +404,9 @@ export class ExpensesAPI extends BaseService {
|
|||
options?: {
|
||||
limit?: number
|
||||
offset?: number
|
||||
days?: number // 5, 30, 60, or 90
|
||||
days?: number // 15, 30, or 60 (default: 15)
|
||||
start_date?: string // ISO format: YYYY-MM-DD
|
||||
end_date?: string // ISO format: YYYY-MM-DD
|
||||
filter_user_id?: string
|
||||
filter_account_type?: string
|
||||
}
|
||||
|
|
@ -415,7 +417,15 @@ export class ExpensesAPI extends BaseService {
|
|||
// Add query parameters
|
||||
if (options?.limit) url.searchParams.set('limit', String(options.limit))
|
||||
if (options?.offset) url.searchParams.set('offset', String(options.offset))
|
||||
if (options?.days) url.searchParams.set('days', String(options.days))
|
||||
|
||||
// Custom date range takes precedence over days
|
||||
if (options?.start_date && options?.end_date) {
|
||||
url.searchParams.set('start_date', options.start_date)
|
||||
url.searchParams.set('end_date', options.end_date)
|
||||
} else if (options?.days) {
|
||||
url.searchParams.set('days', String(options.days))
|
||||
}
|
||||
|
||||
if (options?.filter_user_id)
|
||||
url.searchParams.set('filter_user_id', options.filter_user_id)
|
||||
if (options?.filter_account_type)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import FuzzySearch from '@/components/ui/fuzzy-search/FuzzySearch.vue'
|
|||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import {
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
|
|
@ -25,7 +26,9 @@ const expensesAPI = injectService<ExpensesAPI>(SERVICE_TOKENS.EXPENSES_API)
|
|||
|
||||
const transactions = ref<Transaction[]>([])
|
||||
const isLoading = ref(false)
|
||||
const selectedDays = ref(5)
|
||||
const dateRangeType = ref<number | 'custom'>(15) // 15, 30, 60, or 'custom'
|
||||
const customStartDate = ref<string>('')
|
||||
const customEndDate = ref<string>('')
|
||||
|
||||
const walletKey = computed(() => user.value?.wallets?.[0]?.inkey)
|
||||
|
||||
|
|
@ -62,12 +65,12 @@ function handleSearchResults(results: Transaction[]) {
|
|||
searchResults.value = results
|
||||
}
|
||||
|
||||
// Day filter options
|
||||
const dayOptions = [
|
||||
{ label: '5 days', value: 5 },
|
||||
// Date range options (matching castle LNbits extension)
|
||||
const dateRangeOptions = [
|
||||
{ label: '15 days', value: 15 },
|
||||
{ label: '30 days', value: 30 },
|
||||
{ label: '60 days', value: 60 },
|
||||
{ label: '90 days', value: 90 }
|
||||
{ label: 'Custom', value: 'custom' as const }
|
||||
]
|
||||
|
||||
// Format date for display
|
||||
|
|
@ -113,12 +116,27 @@ async function loadTransactions() {
|
|||
|
||||
isLoading.value = true
|
||||
try {
|
||||
const response = await expensesAPI.getUserTransactions(walletKey.value, {
|
||||
// Build query params - custom date range takes precedence over preset days
|
||||
const params: any = {
|
||||
limit: 1000, // Load all transactions (no pagination needed)
|
||||
offset: 0,
|
||||
days: selectedDays.value
|
||||
})
|
||||
offset: 0
|
||||
}
|
||||
|
||||
if (dateRangeType.value === 'custom') {
|
||||
// Use custom date range
|
||||
if (customStartDate.value && customEndDate.value) {
|
||||
params.start_date = customStartDate.value
|
||||
params.end_date = customEndDate.value
|
||||
} else {
|
||||
// Default to 15 days if custom selected but dates not provided
|
||||
params.days = 15
|
||||
}
|
||||
} else {
|
||||
// Use preset days
|
||||
params.days = dateRangeType.value
|
||||
}
|
||||
|
||||
const response = await expensesAPI.getUserTransactions(walletKey.value, params)
|
||||
transactions.value = response.entries
|
||||
} catch (error) {
|
||||
console.error('Failed to load transactions:', error)
|
||||
|
|
@ -130,10 +148,29 @@ async function loadTransactions() {
|
|||
}
|
||||
}
|
||||
|
||||
// Change day filter
|
||||
function changeDayFilter(days: number) {
|
||||
selectedDays.value = days
|
||||
loadTransactions()
|
||||
// Handle date range type change
|
||||
function onDateRangeTypeChange(value: number | 'custom') {
|
||||
dateRangeType.value = value
|
||||
|
||||
if (value !== 'custom') {
|
||||
// Clear custom dates when switching to preset days
|
||||
customStartDate.value = ''
|
||||
customEndDate.value = ''
|
||||
// Load transactions immediately with preset days
|
||||
loadTransactions()
|
||||
}
|
||||
// If switching to custom, wait for user to provide dates
|
||||
}
|
||||
|
||||
// Apply custom date range
|
||||
function applyCustomDateRange() {
|
||||
if (customStartDate.value && customEndDate.value) {
|
||||
loadTransactions()
|
||||
} else {
|
||||
toast.error('Invalid date range', {
|
||||
description: 'Please select both start and end dates'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
@ -163,20 +200,53 @@ onMounted(() => {
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Compact Controls Row -->
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<Calendar class="h-4 w-4 text-muted-foreground" />
|
||||
<Button
|
||||
v-for="option in dayOptions"
|
||||
:key="option.value"
|
||||
:variant="selectedDays === option.value ? 'default' : 'outline'"
|
||||
size="sm"
|
||||
class="h-8 px-3 text-xs"
|
||||
@click="changeDayFilter(option.value)"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ option.label }}
|
||||
</Button>
|
||||
<!-- Date Range Controls -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<!-- Preset Days / Custom Toggle -->
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<Calendar class="h-4 w-4 text-muted-foreground" />
|
||||
<Button
|
||||
v-for="option in dateRangeOptions"
|
||||
:key="option.value"
|
||||
:variant="dateRangeType === option.value ? 'default' : 'outline'"
|
||||
size="sm"
|
||||
class="h-8 px-3 text-xs"
|
||||
@click="onDateRangeTypeChange(option.value)"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ option.label }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Custom Date Range Inputs -->
|
||||
<div v-if="dateRangeType === 'custom'" class="flex items-end gap-2 flex-wrap">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs text-muted-foreground">From:</label>
|
||||
<Input
|
||||
type="date"
|
||||
v-model="customStartDate"
|
||||
class="h-8 text-xs"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs text-muted-foreground">To:</label>
|
||||
<Input
|
||||
type="date"
|
||||
v-model="customEndDate"
|
||||
class="h-8 text-xs"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
class="h-8 px-3 text-xs"
|
||||
@click="applyCustomDateRange"
|
||||
:disabled="isLoading || !customStartDate || !customEndDate"
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue