Enhances expense submission with user wallet
Updates expense submission to require a user wallet. Retrieves wallet information from the authentication context and includes it in the expense submission request to the backend. This ensures that expenses are correctly associated with the user's wallet, enabling accurate tracking and management of expenses. Also adds error handling and user feedback.
This commit is contained in:
parent
9ed674d0f3
commit
00a99995c9
3 changed files with 47 additions and 59 deletions
|
|
@ -15,7 +15,7 @@ export class ExpensesAPI extends BaseService {
|
|||
protected readonly metadata = {
|
||||
name: 'ExpensesAPI',
|
||||
version: '1.0.0',
|
||||
dependencies: ['AuthService', 'ToastService']
|
||||
dependencies: [] // No dependencies - wallet key is passed as parameter
|
||||
}
|
||||
|
||||
private get config() {
|
||||
|
|
@ -34,18 +34,9 @@ export class ExpensesAPI extends BaseService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get authentication headers
|
||||
* Get authentication headers with provided wallet key
|
||||
*/
|
||||
private getHeaders(): HeadersInit {
|
||||
if (!this.authService) {
|
||||
throw new Error('AuthService not available')
|
||||
}
|
||||
|
||||
const walletKey = this.authService.walletKey
|
||||
if (!walletKey) {
|
||||
throw new Error('Wallet key not available. Please log in.')
|
||||
}
|
||||
|
||||
private getHeaders(walletKey: string): HeadersInit {
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Api-Key': walletKey
|
||||
|
|
@ -58,11 +49,11 @@ export class ExpensesAPI extends BaseService {
|
|||
* Note: Currently returns all accounts. Once castle API implements
|
||||
* user permissions, use filter_by_user=true parameter.
|
||||
*/
|
||||
async getAccounts(): Promise<Account[]> {
|
||||
async getAccounts(walletKey: string): Promise<Account[]> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/v1/accounts`, {
|
||||
const response = await fetch(`${this.baseUrl}/castle/api/v1/accounts`, {
|
||||
method: 'GET',
|
||||
headers: this.getHeaders(),
|
||||
headers: this.getHeaders(walletKey),
|
||||
signal: AbortSignal.timeout(this.config?.apiConfig?.timeout || 30000)
|
||||
})
|
||||
|
||||
|
|
@ -74,11 +65,6 @@ export class ExpensesAPI extends BaseService {
|
|||
return accounts as Account[]
|
||||
} catch (error) {
|
||||
console.error('[ExpensesAPI] Error fetching accounts:', error)
|
||||
if (this.toastService) {
|
||||
this.toastService.error('Failed to load accounts', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error'
|
||||
})
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -89,8 +75,8 @@ export class ExpensesAPI extends BaseService {
|
|||
* Converts flat account list to nested tree based on colon-separated names
|
||||
* e.g., "Expenses:Groceries:Organic" becomes nested structure
|
||||
*/
|
||||
async getAccountHierarchy(rootAccount?: string): Promise<AccountNode[]> {
|
||||
const accounts = await this.getAccounts()
|
||||
async getAccountHierarchy(walletKey: string, rootAccount?: string): Promise<AccountNode[]> {
|
||||
const accounts = await this.getAccounts(walletKey)
|
||||
|
||||
// Filter by root account if specified
|
||||
let filteredAccounts = accounts
|
||||
|
|
@ -151,11 +137,11 @@ export class ExpensesAPI extends BaseService {
|
|||
/**
|
||||
* Submit expense entry to castle
|
||||
*/
|
||||
async submitExpense(request: ExpenseEntryRequest): Promise<ExpenseEntry> {
|
||||
async submitExpense(walletKey: string, request: ExpenseEntryRequest): Promise<ExpenseEntry> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/v1/entries/expense`, {
|
||||
const response = await fetch(`${this.baseUrl}/castle/api/v1/entries/expense`, {
|
||||
method: 'POST',
|
||||
headers: this.getHeaders(),
|
||||
headers: this.getHeaders(walletKey),
|
||||
body: JSON.stringify(request),
|
||||
signal: AbortSignal.timeout(this.config?.apiConfig?.timeout || 30000)
|
||||
})
|
||||
|
|
@ -168,28 +154,9 @@ export class ExpensesAPI extends BaseService {
|
|||
}
|
||||
|
||||
const entry = await response.json()
|
||||
|
||||
if (this.toastService) {
|
||||
this.toastService.success('Expense submitted', {
|
||||
description: 'Your expense is pending admin approval'
|
||||
})
|
||||
}
|
||||
|
||||
return entry as ExpenseEntry
|
||||
} catch (error) {
|
||||
console.error('[ExpensesAPI] Error submitting expense:', error)
|
||||
|
||||
let errorMessage = 'Failed to submit expense'
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message
|
||||
}
|
||||
|
||||
if (this.toastService) {
|
||||
this.toastService.error('Submission failed', {
|
||||
description: errorMessage
|
||||
})
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -197,11 +164,11 @@ export class ExpensesAPI extends BaseService {
|
|||
/**
|
||||
* Get user's expense entries
|
||||
*/
|
||||
async getUserExpenses(): Promise<ExpenseEntry[]> {
|
||||
async getUserExpenses(walletKey: string): Promise<ExpenseEntry[]> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/v1/entries/user`, {
|
||||
const response = await fetch(`${this.baseUrl}/castle/api/v1/entries/user`, {
|
||||
method: 'GET',
|
||||
headers: this.getHeaders(),
|
||||
headers: this.getHeaders(walletKey),
|
||||
signal: AbortSignal.timeout(this.config?.apiConfig?.timeout || 30000)
|
||||
})
|
||||
|
||||
|
|
@ -215,11 +182,6 @@ export class ExpensesAPI extends BaseService {
|
|||
return entries as ExpenseEntry[]
|
||||
} catch (error) {
|
||||
console.error('[ExpensesAPI] Error fetching user expenses:', error)
|
||||
if (this.toastService) {
|
||||
this.toastService.error('Failed to load expenses', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error'
|
||||
})
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -227,11 +189,11 @@ export class ExpensesAPI extends BaseService {
|
|||
/**
|
||||
* Get user's balance with castle
|
||||
*/
|
||||
async getUserBalance(): Promise<{ balance: number; currency: string }> {
|
||||
async getUserBalance(walletKey: string): Promise<{ balance: number; currency: string }> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/v1/balance`, {
|
||||
const response = await fetch(`${this.baseUrl}/castle/api/v1/balance`, {
|
||||
method: 'GET',
|
||||
headers: this.getHeaders(),
|
||||
headers: this.getHeaders(walletKey),
|
||||
signal: AbortSignal.timeout(this.config?.apiConfig?.timeout || 30000)
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue