feat: Refactor API services and UI components
This commit refactors the API service to use a consistent `fetch` wrapper for all requests, improving error handling and authorization logic. It also updates UI components to reflect changes in API endpoints and data structures, particularly around notifications and extraordinary expenses. Docker configurations are removed as they are no longer relevant for this stage of development.
This commit is contained in:
@@ -1,335 +1,287 @@
|
||||
import {
|
||||
Condo, Family, Payment, AppSettings, User, AuthResponse,
|
||||
Ticket, TicketComment, ExtraordinaryExpense, Notice,
|
||||
AlertDefinition, NoticeRead
|
||||
} from '../types';
|
||||
|
||||
import { Family, Payment, AppSettings, User, AlertDefinition, Condo, Notice, NoticeRead, Ticket, TicketAttachment, TicketComment, SmtpConfig, ExtraordinaryExpense } from '../types';
|
||||
const API_URL = '/api';
|
||||
|
||||
// --- CONFIGURATION TOGGLE ---
|
||||
const FORCE_LOCAL_DB = false;
|
||||
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,
|
||||
};
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
TOKEN: 'condo_auth_token',
|
||||
USER: 'condo_user_info',
|
||||
ACTIVE_CONDO_ID: 'condo_active_id',
|
||||
};
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const getAuthHeaders = () => {
|
||||
const token = localStorage.getItem(STORAGE_KEYS.TOKEN);
|
||||
return token ? { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } : { 'Content-Type': 'application/json' };
|
||||
};
|
||||
const response = await fetch(`${API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
|
||||
const request = async <T>(endpoint: string, options: RequestInit = {}): Promise<T> => {
|
||||
const response = await fetch(`${API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
...getAuthHeaders(),
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(errorText || response.statusText);
|
||||
}
|
||||
|
||||
if (response.status === 401) {
|
||||
CondoService.logout();
|
||||
throw new Error("Unauthorized");
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errText = await response.text();
|
||||
throw new Error(errText || `API Error: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
};
|
||||
// Handle empty responses
|
||||
const text = await response.text();
|
||||
return text ? JSON.parse(text) : undefined;
|
||||
}
|
||||
|
||||
export const CondoService = {
|
||||
|
||||
// --- CONDO CONTEXT MANAGEMENT ---
|
||||
|
||||
getActiveCondoId: (): string | null => {
|
||||
return localStorage.getItem(STORAGE_KEYS.ACTIVE_CONDO_ID);
|
||||
},
|
||||
|
||||
setActiveCondo: (condoId: string) => {
|
||||
localStorage.setItem(STORAGE_KEYS.ACTIVE_CONDO_ID, condoId);
|
||||
window.location.reload();
|
||||
},
|
||||
|
||||
getCondos: async (): Promise<Condo[]> => {
|
||||
return request<Condo[]>('/condos');
|
||||
},
|
||||
|
||||
getActiveCondo: async (): Promise<Condo | undefined> => {
|
||||
const condos = await CondoService.getCondos();
|
||||
const activeId = CondoService.getActiveCondoId();
|
||||
if (!activeId && condos.length > 0) {
|
||||
// Do not reload here, just set it silently or let the UI handle it
|
||||
localStorage.setItem(STORAGE_KEYS.ACTIVE_CONDO_ID, condos[0].id);
|
||||
return condos[0];
|
||||
}
|
||||
return condos.find(c => c.id === activeId);
|
||||
},
|
||||
|
||||
saveCondo: async (condo: Condo): Promise<Condo> => {
|
||||
// If no ID, it's a creation
|
||||
if (!condo.id || condo.id.length < 5) { // Simple check if it's a new ID request
|
||||
return request<Condo>('/condos', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(condo)
|
||||
});
|
||||
} else {
|
||||
return request<Condo>(`/condos/${condo.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(condo)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteCondo: async (id: string) => {
|
||||
await request(`/condos/${id}`, { method: 'DELETE' });
|
||||
if (localStorage.getItem(STORAGE_KEYS.ACTIVE_CONDO_ID) === id) {
|
||||
localStorage.removeItem(STORAGE_KEYS.ACTIVE_CONDO_ID);
|
||||
}
|
||||
},
|
||||
|
||||
// --- NOTICES (BACHECA) ---
|
||||
|
||||
getNotices: async (condoId?: string): Promise<Notice[]> => {
|
||||
let url = '/notices';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
return request<Notice[]>(url);
|
||||
},
|
||||
|
||||
saveNotice: async (notice: Notice): Promise<Notice> => {
|
||||
if (!notice.id) {
|
||||
return request<Notice>('/notices', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(notice)
|
||||
});
|
||||
} else {
|
||||
return request<Notice>(`/notices/${notice.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(notice)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteNotice: async (id: string) => {
|
||||
await request(`/notices/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
markNoticeAsRead: async (noticeId: string, userId: string) => {
|
||||
await request(`/notices/${noticeId}/read`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId })
|
||||
});
|
||||
},
|
||||
|
||||
getNoticeReadStatus: async (noticeId: string): Promise<NoticeRead[]> => {
|
||||
return request<NoticeRead[]>(`/notices/${noticeId}/reads`);
|
||||
},
|
||||
|
||||
getUnreadNoticesForUser: async (userId: string, condoId: string): Promise<Notice[]> => {
|
||||
return request<Notice[]>(`/notices/unread?userId=${userId}&condoId=${condoId}`);
|
||||
},
|
||||
|
||||
// --- AUTH ---
|
||||
|
||||
login: async (email, password) => {
|
||||
const data = await request<{token: string, user: User}>('/auth/login', {
|
||||
// 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(STORAGE_KEYS.TOKEN, data.token);
|
||||
localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(data.user));
|
||||
|
||||
// Set active condo if user belongs to a family
|
||||
if (data.user.familyId) {
|
||||
try {
|
||||
const families = await CondoService.getFamilies(); // This will filter by user perms automatically on server
|
||||
const fam = families.find(f => f.id === data.user.familyId);
|
||||
if (fam) {
|
||||
localStorage.setItem(STORAGE_KEYS.ACTIVE_CONDO_ID, fam.condoId);
|
||||
}
|
||||
} catch (e) { console.error("Could not set active condo on login", e); }
|
||||
}
|
||||
|
||||
return data;
|
||||
localStorage.setItem('condo_token', data.token);
|
||||
localStorage.setItem('condo_user', JSON.stringify(data.user));
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
localStorage.removeItem(STORAGE_KEYS.TOKEN);
|
||||
localStorage.removeItem(STORAGE_KEYS.USER);
|
||||
window.location.href = '#/login';
|
||||
localStorage.removeItem('condo_token');
|
||||
localStorage.removeItem('condo_user');
|
||||
window.location.href = '/#/login';
|
||||
},
|
||||
|
||||
getCurrentUser: (): User | null => {
|
||||
const u = localStorage.getItem(STORAGE_KEYS.USER);
|
||||
return u ? JSON.parse(u) : null;
|
||||
const u = localStorage.getItem('condo_user');
|
||||
return u ? JSON.parse(u) : null;
|
||||
},
|
||||
|
||||
updateProfile: async (data: Partial<User> & { password?: string }) => {
|
||||
return request<{success: true, user: User}>('/profile', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
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 (Global) ---
|
||||
|
||||
// Settings
|
||||
getSettings: async (): Promise<AppSettings> => {
|
||||
return request<AppSettings>('/settings');
|
||||
return request<AppSettings>('/settings');
|
||||
},
|
||||
|
||||
updateSettings: async (settings: AppSettings): Promise<void> => {
|
||||
await request('/settings', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(settings)
|
||||
});
|
||||
return request('/settings', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(settings)
|
||||
});
|
||||
},
|
||||
|
||||
testSmtpConfig: async (config: SmtpConfig): Promise<void> => {
|
||||
await request('/settings/smtp-test', {
|
||||
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');
|
||||
return request<number[]>('/years');
|
||||
},
|
||||
|
||||
// --- FAMILIES ---
|
||||
// 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);
|
||||
let url = '/families';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
return request<Family[]>(url);
|
||||
},
|
||||
|
||||
addFamily: async (familyData: Omit<Family, 'id' | 'balance' | 'condoId'>): Promise<Family> => {
|
||||
const activeCondoId = CondoService.getActiveCondoId();
|
||||
if (!activeCondoId) throw new Error("Nessun condominio selezionato");
|
||||
|
||||
return request<Family>('/families', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ ...familyData, condoId: activeCondoId })
|
||||
});
|
||||
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<Family> => {
|
||||
return request<Family>(`/families/${family.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(family)
|
||||
});
|
||||
updateFamily: async (family: Family): Promise<void> => {
|
||||
return request(`/families/${family.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(family)
|
||||
});
|
||||
},
|
||||
|
||||
deleteFamily: async (familyId: string): Promise<void> => {
|
||||
await request(`/families/${familyId}`, { method: 'DELETE' });
|
||||
deleteFamily: async (id: string): Promise<void> => {
|
||||
return request(`/families/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
// --- PAYMENTS ---
|
||||
// Payments
|
||||
seedPayments: () => { /* No-op for real backend */ },
|
||||
|
||||
getPaymentsByFamily: async (familyId: string): Promise<Payment[]> => {
|
||||
return request<Payment[]>(`/payments?familyId=${familyId}`);
|
||||
return request<Payment[]>(`/payments?familyId=${familyId}`);
|
||||
},
|
||||
|
||||
getCondoPayments: async (condoId: string): Promise<Payment[]> => {
|
||||
return request<Payment[]>(`/payments?condoId=${condoId}`);
|
||||
},
|
||||
|
||||
addPayment: async (payment: Omit<Payment, 'id'>): Promise<Payment> => {
|
||||
return request<Payment>('/payments', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payment)
|
||||
});
|
||||
},
|
||||
|
||||
// --- USERS ---
|
||||
|
||||
getUsers: async (condoId?: string): Promise<User[]> => {
|
||||
let url = '/users';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
return request<User[]>(url);
|
||||
},
|
||||
|
||||
createUser: async (userData: any) => {
|
||||
return request('/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(userData)
|
||||
});
|
||||
},
|
||||
|
||||
updateUser: async (id: string, userData: any) => {
|
||||
return request(`/users/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(userData)
|
||||
addPayment: async (payment: any): Promise<Payment> => {
|
||||
return request<Payment>('/payments', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payment)
|
||||
});
|
||||
},
|
||||
|
||||
deleteUser: async (id: string) => {
|
||||
await request(`/users/${id}`, { method: 'DELETE' });
|
||||
// Users
|
||||
getUsers: async (condoId?: string): Promise<User[]> => {
|
||||
let url = '/users';
|
||||
if (condoId) url += `?condoId=${condoId}`;
|
||||
return request<User[]>(url);
|
||||
},
|
||||
|
||||
// --- ALERTS ---
|
||||
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';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
if (condoId) url += `?condoId=${condoId}`;
|
||||
return request<AlertDefinition[]>(url);
|
||||
},
|
||||
|
||||
saveAlert: async (alert: AlertDefinition & { condoId?: string }): Promise<AlertDefinition> => {
|
||||
const activeCondoId = CondoService.getActiveCondoId();
|
||||
if (!alert.id) {
|
||||
return request<AlertDefinition>('/alerts', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ ...alert, condoId: activeCondoId })
|
||||
});
|
||||
} else {
|
||||
return request<AlertDefinition>(`/alerts/${alert.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(alert)
|
||||
});
|
||||
}
|
||||
|
||||
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) => {
|
||||
await request(`/alerts/${id}`, { method: 'DELETE' });
|
||||
deleteAlert: async (id: string): Promise<void> => {
|
||||
return request(`/alerts/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
// --- TICKETS ---
|
||||
|
||||
getTickets: async (condoId?: string): Promise<Ticket[]> => {
|
||||
let url = '/tickets';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
return request<Ticket[]>(url);
|
||||
// Notices
|
||||
getNotices: async (condoId?: string): Promise<Notice[]> => {
|
||||
let url = '/notices';
|
||||
const activeId = condoId || CondoService.getActiveCondoId();
|
||||
if (activeId) url += `?condoId=${activeId}`;
|
||||
return request<Notice[]>(url);
|
||||
},
|
||||
|
||||
createTicket: async (data: Omit<Partial<Ticket>, 'attachments'> & { attachments?: { fileName: string, fileType: string, data: string }[] }) => {
|
||||
const activeId = CondoService.getActiveCondoId();
|
||||
if(!activeId) throw new Error("No active condo");
|
||||
return request('/tickets', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ ...data, condoId: activeId })
|
||||
});
|
||||
getUnreadNoticesForUser: async (userId: string, condoId: string): Promise<Notice[]> => {
|
||||
return request<Notice[]>(`/notices/unread?userId=${userId}&condoId=${condoId}`);
|
||||
},
|
||||
|
||||
updateTicket: async (id: string, data: { status: string, priority: string }) => {
|
||||
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) => {
|
||||
await request(`/tickets/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
getTicketAttachment: async (ticketId: string, attachmentId: string): Promise<TicketAttachment> => {
|
||||
return request<TicketAttachment>(`/tickets/${ticketId}/attachments/${attachmentId}`);
|
||||
deleteTicket: async (id: string): Promise<void> => {
|
||||
return request(`/tickets/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
getTicketComments: async (ticketId: string): Promise<TicketComment[]> => {
|
||||
@@ -337,14 +289,17 @@ export const CondoService = {
|
||||
},
|
||||
|
||||
addTicketComment: async (ticketId: string, text: string): Promise<void> => {
|
||||
await request(`/tickets/${ticketId}/comments`, {
|
||||
return request(`/tickets/${ticketId}/comments`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ text })
|
||||
});
|
||||
},
|
||||
|
||||
// --- EXTRAORDINARY EXPENSES ---
|
||||
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();
|
||||
@@ -365,6 +320,13 @@ export const CondoService = {
|
||||
});
|
||||
},
|
||||
|
||||
updateExpense: async (id: string, data: any): Promise<void> => {
|
||||
return request(`/expenses/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
},
|
||||
|
||||
getExpenseAttachment: async (expenseId: string, attachmentId: string): Promise<any> => {
|
||||
return request(`/expenses/${expenseId}/attachments/${attachmentId}`);
|
||||
},
|
||||
@@ -379,10 +341,5 @@ export const CondoService = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ amount, notes: 'PayPal Payment' })
|
||||
});
|
||||
},
|
||||
|
||||
// --- SEEDING ---
|
||||
seedPayments: () => {
|
||||
// No-op in remote mode
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user