155 lines
4.9 KiB
TypeScript
155 lines
4.9 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { apiClient, API_ENDPOINTS } from '@/config/api'
|
|
import type {
|
|
Expense,
|
|
ExpenseSplit,
|
|
SettlementActivity,
|
|
SettlementActivityPublic,
|
|
} from '@/types/expense'
|
|
import type { SettlementActivityCreate } from '@/types/expense'
|
|
import type { List } from '@/types/list'
|
|
import type { AxiosResponse } from 'axios'
|
|
|
|
export interface ListWithExpenses extends List {
|
|
id: number
|
|
expenses: Expense[]
|
|
}
|
|
|
|
interface ListDetailState {
|
|
currentList: ListWithExpenses | null
|
|
isLoading: boolean
|
|
error: string | null
|
|
isSettlingSplit: boolean
|
|
}
|
|
|
|
export const useListDetailStore = defineStore('listDetail', {
|
|
state: (): ListDetailState => ({
|
|
currentList: null,
|
|
isLoading: false,
|
|
error: null,
|
|
isSettlingSplit: false,
|
|
}),
|
|
|
|
actions: {
|
|
async fetchListWithExpenses(listId: string) {
|
|
this.isLoading = true
|
|
this.error = null
|
|
try {
|
|
// Get list details
|
|
const listEndpoint = API_ENDPOINTS.LISTS.BY_ID(listId)
|
|
const listResponse = await apiClient.get(listEndpoint)
|
|
const listData = listResponse.data as List
|
|
|
|
// Get expenses for this list
|
|
const expensesEndpoint = API_ENDPOINTS.LISTS.EXPENSES(listId)
|
|
const expensesResponse = await apiClient.get(expensesEndpoint)
|
|
const expensesData = expensesResponse.data as Expense[]
|
|
|
|
// Combine into ListWithExpenses
|
|
this.currentList = {
|
|
...listData,
|
|
expenses: expensesData,
|
|
} as ListWithExpenses
|
|
} catch (err: any) {
|
|
this.error = err.response?.data?.detail || err.message || 'Failed to fetch list details'
|
|
this.currentList = null
|
|
console.error('Error fetching list details:', err)
|
|
} finally {
|
|
this.isLoading = false
|
|
}
|
|
},
|
|
|
|
async settleExpenseSplit(payload: {
|
|
list_id_for_refetch: string // ID of the list to refetch after settlement
|
|
expense_split_id: number
|
|
activity_data: SettlementActivityCreate
|
|
}): Promise<boolean> {
|
|
this.isSettlingSplit = true
|
|
this.error = null
|
|
try {
|
|
// Call the actual API endpoint using generic post method
|
|
const endpoint = `/financials/expense_splits/${payload.expense_split_id}/settle`
|
|
const response = await apiClient.post(endpoint, payload.activity_data)
|
|
|
|
// Refresh list data to show updated statuses
|
|
if (payload.list_id_for_refetch) {
|
|
await this.fetchListWithExpenses(payload.list_id_for_refetch)
|
|
} else if (this.currentList?.id) {
|
|
// Fallback if list_id_for_refetch is not provided but currentList exists
|
|
await this.fetchListWithExpenses(String(this.currentList.id))
|
|
} else {
|
|
console.warn(
|
|
'Could not refetch list details: list_id_for_refetch not provided and no currentList available.',
|
|
)
|
|
}
|
|
|
|
this.isSettlingSplit = false
|
|
return true // Indicate success
|
|
} catch (err: any) {
|
|
const errorMessage =
|
|
err.response?.data?.detail || err.message || 'Failed to settle expense split.'
|
|
this.error = errorMessage
|
|
console.error('Error settling expense split:', err)
|
|
this.isSettlingSplit = false
|
|
return false // Indicate failure
|
|
}
|
|
},
|
|
|
|
setError(errorMessage: string) {
|
|
this.error = errorMessage
|
|
this.isLoading = false
|
|
},
|
|
},
|
|
|
|
getters: {
|
|
getList(state: ListDetailState): ListWithExpenses | null {
|
|
return state.currentList
|
|
},
|
|
getExpenses(state: ListDetailState): Expense[] {
|
|
return state.currentList?.expenses || []
|
|
},
|
|
getPaidAmountForSplit:
|
|
(state: ListDetailState) =>
|
|
(splitId: number): number => {
|
|
let totalPaid = 0
|
|
if (state.currentList && state.currentList.expenses) {
|
|
for (const expense of state.currentList.expenses) {
|
|
const split = expense.splits.find((s) => s.id === splitId)
|
|
if (split && split.settlement_activities) {
|
|
totalPaid = split.settlement_activities.reduce((sum, activity) => {
|
|
return sum + parseFloat(activity.amount_paid)
|
|
}, 0)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return totalPaid
|
|
},
|
|
getExpenseSplitById:
|
|
(state: ListDetailState) =>
|
|
(splitId: number): ExpenseSplit | undefined => {
|
|
if (!state.currentList || !state.currentList.expenses) return undefined
|
|
for (const expense of state.currentList.expenses) {
|
|
const split = expense.splits.find((s) => s.id === splitId)
|
|
if (split) return split
|
|
}
|
|
return undefined
|
|
},
|
|
},
|
|
})
|
|
|
|
// Assuming List interface might be defined in fe/src/types/list.ts
|
|
// If not, it should be defined like this:
|
|
/*
|
|
export interface List {
|
|
id: number;
|
|
name: string;
|
|
description?: string | null;
|
|
is_complete: boolean;
|
|
group_id?: number | null;
|
|
// items: Item[]; // Item interface would also need to be defined
|
|
// version: number;
|
|
// updated_at: string;
|
|
}
|
|
*/
|