Files
Condopay/services/mockDb.ts
frakarr 8a43143ead feat(expenses): Add delete expense endpoint and functionality
Implements the ability to delete an expense, including its associated items and shares. Also refactors the expense update logic to correctly handle share updates and adds the corresponding API endpoint and mock DB function.
2025-12-09 23:25:06 +01:00

353 lines
10 KiB
TypeScript

import {
Condo, Family, Payment, AppSettings, User, AuthResponse,
Ticket, TicketComment, ExtraordinaryExpense, Notice,
AlertDefinition, NoticeRead
} from '../types';
const API_URL = '/api';
async function request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const token = localStorage.getItem('condo_token');
const headers: HeadersInit = {
'Content-Type': 'application/json',
...options.headers as any,
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(`${API_URL}${endpoint}`, {
...options,
headers,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText || response.statusText);
}
// Handle empty responses
const text = await response.text();
return text ? JSON.parse(text) : undefined;
}
export const CondoService = {
// Auth & User
login: async (email: string, password: string): Promise<void> => {
const data = await request<AuthResponse>('/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
localStorage.setItem('condo_token', data.token);
localStorage.setItem('condo_user', JSON.stringify(data.user));
},
logout: () => {
localStorage.removeItem('condo_token');
localStorage.removeItem('condo_user');
window.location.href = '/#/login';
},
getCurrentUser: (): User | null => {
const u = localStorage.getItem('condo_user');
return u ? JSON.parse(u) : null;
},
updateProfile: async (data: any): Promise<void> => {
const res = await request<{success: boolean, user: User}>('/profile', {
method: 'PUT',
body: JSON.stringify(data)
});
if (res.user) {
localStorage.setItem('condo_user', JSON.stringify(res.user));
}
},
// Settings
getSettings: async (): Promise<AppSettings> => {
return request<AppSettings>('/settings');
},
updateSettings: async (settings: AppSettings): Promise<void> => {
return request('/settings', {
method: 'PUT',
body: JSON.stringify(settings)
});
},
testSmtpConfig: async (config: any): Promise<void> => {
return request('/settings/smtp-test', {
method: 'POST',
body: JSON.stringify(config)
});
},
getAvailableYears: async (): Promise<number[]> => {
return request<number[]>('/years');
},
// Condos
getCondos: async (): Promise<Condo[]> => {
return request<Condo[]>('/condos');
},
getActiveCondoId: (): string | undefined => {
return localStorage.getItem('active_condo_id') || undefined;
},
getActiveCondo: async (): Promise<Condo | undefined> => {
const id = localStorage.getItem('active_condo_id');
const condos = await CondoService.getCondos();
if (id) {
return condos.find(c => c.id === id);
}
return condos.length > 0 ? condos[0] : undefined;
},
setActiveCondo: (id: string) => {
localStorage.setItem('active_condo_id', id);
window.dispatchEvent(new Event('condo-updated'));
window.location.reload();
},
saveCondo: async (condo: Condo): Promise<Condo> => {
if (condo.id) {
await request(`/condos/${condo.id}`, {
method: 'PUT',
body: JSON.stringify(condo)
});
return condo;
} else {
return request<Condo>('/condos', {
method: 'POST',
body: JSON.stringify(condo)
});
}
},
deleteCondo: async (id: string): Promise<void> => {
return request(`/condos/${id}`, { method: 'DELETE' });
},
// Families
getFamilies: async (condoId?: string): Promise<Family[]> => {
let url = '/families';
const activeId = condoId || CondoService.getActiveCondoId();
if (activeId) url += `?condoId=${activeId}`;
return request<Family[]>(url);
},
addFamily: async (family: any): Promise<Family> => {
const activeId = CondoService.getActiveCondoId();
return request<Family>('/families', {
method: 'POST',
body: JSON.stringify({ ...family, condoId: activeId })
});
},
updateFamily: async (family: Family): Promise<void> => {
return request(`/families/${family.id}`, {
method: 'PUT',
body: JSON.stringify(family)
});
},
deleteFamily: async (id: string): Promise<void> => {
return request(`/families/${id}`, { method: 'DELETE' });
},
// Payments
seedPayments: () => { /* No-op for real backend */ },
getPaymentsByFamily: async (familyId: string): Promise<Payment[]> => {
return request<Payment[]>(`/payments?familyId=${familyId}`);
},
getCondoPayments: async (condoId: string): Promise<Payment[]> => {
return request<Payment[]>(`/payments?condoId=${condoId}`);
},
addPayment: async (payment: any): Promise<Payment> => {
return request<Payment>('/payments', {
method: 'POST',
body: JSON.stringify(payment)
});
},
// Users
getUsers: async (condoId?: string): Promise<User[]> => {
let url = '/users';
if (condoId) url += `?condoId=${condoId}`;
return request<User[]>(url);
},
createUser: async (user: any): Promise<void> => {
return request('/users', {
method: 'POST',
body: JSON.stringify(user)
});
},
updateUser: async (id: string, user: any): Promise<void> => {
return request(`/users/${id}`, {
method: 'PUT',
body: JSON.stringify(user)
});
},
deleteUser: async (id: string): Promise<void> => {
return request(`/users/${id}`, { method: 'DELETE' });
},
// Alerts
getAlerts: async (condoId?: string): Promise<AlertDefinition[]> => {
let url = '/alerts';
if (condoId) url += `?condoId=${condoId}`;
return request<AlertDefinition[]>(url);
},
saveAlert: async (alert: AlertDefinition): Promise<AlertDefinition> => {
const activeId = CondoService.getActiveCondoId();
if (alert.id) {
await request(`/alerts/${alert.id}`, { method: 'PUT', body: JSON.stringify(alert) });
return alert;
} else {
return request('/alerts', {
method: 'POST',
body: JSON.stringify({ ...alert, condoId: activeId })
});
}
},
deleteAlert: async (id: string): Promise<void> => {
return request(`/alerts/${id}`, { method: 'DELETE' });
},
// Notices
getNotices: async (condoId?: string): Promise<Notice[]> => {
let url = '/notices';
const activeId = condoId || CondoService.getActiveCondoId();
if (activeId) url += `?condoId=${activeId}`;
return request<Notice[]>(url);
},
getUnreadNoticesForUser: async (userId: string, condoId: string): Promise<Notice[]> => {
return request<Notice[]>(`/notices/unread?userId=${userId}&condoId=${condoId}`);
},
getNoticeReadStatus: async (noticeId: string): Promise<NoticeRead[]> => {
return request<NoticeRead[]>(`/notices/${noticeId}/read-status`);
},
markNoticeAsRead: async (noticeId: string, userId: string): Promise<void> => {
return request(`/notices/${noticeId}/read`, {
method: 'POST',
body: JSON.stringify({ userId })
});
},
saveNotice: async (notice: Notice): Promise<void> => {
if (notice.id) {
return request(`/notices/${notice.id}`, { method: 'PUT', body: JSON.stringify(notice) });
} else {
return request('/notices', { method: 'POST', body: JSON.stringify(notice) });
}
},
deleteNotice: async (id: string): Promise<void> => {
return request(`/notices/${id}`, { method: 'DELETE' });
},
// Tickets
getTickets: async (): Promise<Ticket[]> => {
const activeId = CondoService.getActiveCondoId();
return request<Ticket[]>(`/tickets?condoId=${activeId}`);
},
createTicket: async (data: any): Promise<void> => {
const activeId = CondoService.getActiveCondoId();
return request('/tickets', {
method: 'POST',
body: JSON.stringify({ ...data, condoId: activeId })
});
},
updateTicket: async (id: string, data: any): Promise<void> => {
return request(`/tickets/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
});
},
deleteTicket: async (id: string): Promise<void> => {
return request(`/tickets/${id}`, { method: 'DELETE' });
},
getTicketComments: async (ticketId: string): Promise<TicketComment[]> => {
return request<TicketComment[]>(`/tickets/${ticketId}/comments`);
},
addTicketComment: async (ticketId: string, text: string): Promise<void> => {
return request(`/tickets/${ticketId}/comments`, {
method: 'POST',
body: JSON.stringify({ text })
});
},
getTicketAttachment: async (ticketId: string, attachmentId: string): Promise<any> => {
return request(`/tickets/${ticketId}/attachments/${attachmentId}`);
},
// Extraordinary Expenses
getExpenses: async (condoId?: string): Promise<ExtraordinaryExpense[]> => {
let url = '/expenses';
const activeId = condoId || CondoService.getActiveCondoId();
if (activeId) url += `?condoId=${activeId}`;
return request<ExtraordinaryExpense[]>(url);
},
getExpenseDetails: async (id: string): Promise<ExtraordinaryExpense> => {
return request<ExtraordinaryExpense>(`/expenses/${id}`);
},
createExpense: async (data: any): Promise<void> => {
const activeId = CondoService.getActiveCondoId();
if (!activeId) throw new Error("No active condo");
return request('/expenses', {
method: 'POST',
body: JSON.stringify({ ...data, condoId: activeId })
});
},
updateExpense: async (id: string, data: any): Promise<void> => {
return request(`/expenses/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
});
},
deleteExpense: async (id: string): Promise<void> => {
return request(`/expenses/${id}`, {
method: 'DELETE'
});
},
getExpenseAttachment: async (expenseId: string, attachmentId: string): Promise<any> => {
return request(`/expenses/${expenseId}/attachments/${attachmentId}`);
},
getMyExpenses: async (): Promise<any[]> => {
const activeId = CondoService.getActiveCondoId();
return request(`/my-expenses?condoId=${activeId}`);
},
payExpense: async (expenseId: string, amount: number): Promise<void> => {
return request(`/expenses/${expenseId}/pay`, {
method: 'POST',
body: JSON.stringify({ amount, notes: 'PayPal Payment' })
});
}
};