mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 23:06:41 +02:00
chore: archive finance, mail, moodlit apps and rename voxel-lava
- Move finance, mail, moodlit to apps-archived for later development - Rename games/voxel-lava to games/voxelava 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c3c272abc9
commit
ace7fa8f7f
427 changed files with 0 additions and 0 deletions
25
apps-archived/finance/apps/web/src/lib/api/accounts.ts
Normal file
25
apps-archived/finance/apps/web/src/lib/api/accounts.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { apiClient } from './client';
|
||||
import type { Account, CreateAccountInput, UpdateAccountInput } from '@finance/shared';
|
||||
|
||||
export const accountsApi = {
|
||||
getAll: () => apiClient.get<Account[]>('/accounts'),
|
||||
|
||||
getAllIncludingArchived: () => apiClient.get<Account[]>('/accounts/all'),
|
||||
|
||||
getOne: (id: string) => apiClient.get<Account>(`/accounts/${id}`),
|
||||
|
||||
getTotals: () =>
|
||||
apiClient.get<{ currency: string; total: number; count: number }[]>('/accounts/totals'),
|
||||
|
||||
create: (data: CreateAccountInput) => apiClient.post<Account>('/accounts', data),
|
||||
|
||||
update: (id: string, data: UpdateAccountInput) => apiClient.put<Account>(`/accounts/${id}`, data),
|
||||
|
||||
delete: (id: string) => apiClient.delete<{ success: boolean }>(`/accounts/${id}`),
|
||||
|
||||
archive: (id: string) => apiClient.post<Account>(`/accounts/${id}/archive`),
|
||||
|
||||
unarchive: (id: string) => apiClient.post<Account>(`/accounts/${id}/unarchive`),
|
||||
|
||||
reorder: (accountIds: string[]) => apiClient.put<Account[]>('/accounts/reorder', { accountIds }),
|
||||
};
|
||||
43
apps-archived/finance/apps/web/src/lib/api/budgets.ts
Normal file
43
apps-archived/finance/apps/web/src/lib/api/budgets.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { apiClient } from './client';
|
||||
import type { Budget, CreateBudgetInput, UpdateBudgetInput } from '@finance/shared';
|
||||
|
||||
// Budget with computed spending fields from API
|
||||
export interface BudgetWithSpending {
|
||||
id: string;
|
||||
userId: string;
|
||||
categoryId: string | null;
|
||||
month: number;
|
||||
year: number;
|
||||
amount: string;
|
||||
alertThreshold: string;
|
||||
rolloverEnabled: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
spent: number;
|
||||
remaining: number;
|
||||
percentage: number;
|
||||
category?: {
|
||||
id: string;
|
||||
name: string;
|
||||
color: string;
|
||||
icon?: string;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export const budgetsApi = {
|
||||
getAll: () => apiClient.get<Budget[]>('/budgets'),
|
||||
|
||||
getByMonth: (year: number, month: number) =>
|
||||
apiClient.get<BudgetWithSpending[]>(`/budgets/month/${year}/${month}`),
|
||||
|
||||
getOne: (id: string) => apiClient.get<Budget>(`/budgets/${id}`),
|
||||
|
||||
create: (data: CreateBudgetInput) => apiClient.post<Budget>('/budgets', data),
|
||||
|
||||
update: (id: string, data: UpdateBudgetInput) => apiClient.put<Budget>(`/budgets/${id}`, data),
|
||||
|
||||
delete: (id: string) => apiClient.delete<{ success: boolean }>(`/budgets/${id}`),
|
||||
|
||||
copyFromPreviousMonth: (year: number, month: number) =>
|
||||
apiClient.post<{ message: string; copied: number }>('/budgets/copy', { year, month }),
|
||||
};
|
||||
30
apps-archived/finance/apps/web/src/lib/api/categories.ts
Normal file
30
apps-archived/finance/apps/web/src/lib/api/categories.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { apiClient } from './client';
|
||||
import type {
|
||||
Category,
|
||||
CreateCategoryInput,
|
||||
UpdateCategoryInput,
|
||||
CategoryType,
|
||||
} from '@finance/shared';
|
||||
|
||||
export const categoriesApi = {
|
||||
getAll: (type?: CategoryType) => {
|
||||
const params = type ? `?type=${type}` : '';
|
||||
return apiClient.get<Category[]>(`/categories${params}`);
|
||||
},
|
||||
|
||||
getAllIncludingArchived: () => apiClient.get<Category[]>('/categories/all'),
|
||||
|
||||
getTree: () => apiClient.get<(Category & { children: Category[] })[]>('/categories/tree'),
|
||||
|
||||
getOne: (id: string) => apiClient.get<Category>(`/categories/${id}`),
|
||||
|
||||
create: (data: CreateCategoryInput) => apiClient.post<Category>('/categories', data),
|
||||
|
||||
update: (id: string, data: UpdateCategoryInput) =>
|
||||
apiClient.put<Category>(`/categories/${id}`, data),
|
||||
|
||||
delete: (id: string) => apiClient.delete<{ success: boolean }>(`/categories/${id}`),
|
||||
|
||||
seed: () =>
|
||||
apiClient.post<{ message: string; seeded: boolean; count?: number }>('/categories/seed'),
|
||||
};
|
||||
61
apps-archived/finance/apps/web/src/lib/api/client.ts
Normal file
61
apps-archived/finance/apps/web/src/lib/api/client.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { PUBLIC_BACKEND_URL } from '$env/static/public';
|
||||
|
||||
class ApiClient {
|
||||
private baseUrl: string;
|
||||
private token: string | null = null;
|
||||
|
||||
constructor() {
|
||||
this.baseUrl = PUBLIC_BACKEND_URL || 'http://localhost:3019';
|
||||
}
|
||||
|
||||
setToken(token: string | null) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
method: string,
|
||||
path: string,
|
||||
body?: unknown,
|
||||
options?: RequestInit
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}/api/v1${path}`;
|
||||
|
||||
const headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
...(this.token && { Authorization: `Bearer ${this.token}` }),
|
||||
...options?.headers,
|
||||
};
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
...options,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Request failed' }));
|
||||
throw new Error(error.message || `HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
get<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
return this.request<T>('GET', path, undefined, options);
|
||||
}
|
||||
|
||||
post<T>(path: string, body?: unknown, options?: RequestInit): Promise<T> {
|
||||
return this.request<T>('POST', path, body, options);
|
||||
}
|
||||
|
||||
put<T>(path: string, body?: unknown, options?: RequestInit): Promise<T> {
|
||||
return this.request<T>('PUT', path, body, options);
|
||||
}
|
||||
|
||||
delete<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
return this.request<T>('DELETE', path, undefined, options);
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient();
|
||||
25
apps-archived/finance/apps/web/src/lib/api/exchange-rates.ts
Normal file
25
apps-archived/finance/apps/web/src/lib/api/exchange-rates.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { apiClient } from './client';
|
||||
|
||||
interface ExchangeRate {
|
||||
fromCurrency: string;
|
||||
toCurrency: string;
|
||||
rate: number;
|
||||
date: string;
|
||||
}
|
||||
|
||||
export const exchangeRatesApi = {
|
||||
getAll: (baseCurrency = 'EUR') =>
|
||||
apiClient.get<ExchangeRate[]>(`/exchange-rates?base=${baseCurrency}`),
|
||||
|
||||
getRate: (fromCurrency: string, toCurrency: string) =>
|
||||
apiClient.get<number>(`/exchange-rates/rate?from=${fromCurrency}&to=${toCurrency}`),
|
||||
|
||||
convert: (amount: number, fromCurrency: string, toCurrency: string) =>
|
||||
apiClient.get<number>(
|
||||
`/exchange-rates/convert?amount=${amount}&from=${fromCurrency}&to=${toCurrency}`
|
||||
),
|
||||
|
||||
seed: () => apiClient.post<{ message: string; seeded: boolean }>('/exchange-rates/seed'),
|
||||
|
||||
fetch: () => apiClient.post<void>('/exchange-rates/fetch'),
|
||||
};
|
||||
9
apps-archived/finance/apps/web/src/lib/api/index.ts
Normal file
9
apps-archived/finance/apps/web/src/lib/api/index.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export { apiClient } from './client';
|
||||
export { accountsApi } from './accounts';
|
||||
export { categoriesApi } from './categories';
|
||||
export { transactionsApi } from './transactions';
|
||||
export { budgetsApi } from './budgets';
|
||||
export { transfersApi } from './transfers';
|
||||
export { reportsApi } from './reports';
|
||||
export { settingsApi } from './settings';
|
||||
export { exchangeRatesApi } from './exchange-rates';
|
||||
89
apps-archived/finance/apps/web/src/lib/api/reports.ts
Normal file
89
apps-archived/finance/apps/web/src/lib/api/reports.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { apiClient } from './client';
|
||||
import type { DashboardData, MonthlySummary, CategoryBreakdown, TrendData } from '@finance/shared';
|
||||
|
||||
interface Dashboard {
|
||||
totals: { currency: string; amount: number }[];
|
||||
currentMonth: {
|
||||
year: number;
|
||||
month: number;
|
||||
income: number;
|
||||
expense: number;
|
||||
net: number;
|
||||
};
|
||||
budgets: {
|
||||
id: string;
|
||||
category: { id: string; name: string; color: string } | null;
|
||||
amount: number;
|
||||
spent: number;
|
||||
percentage: number;
|
||||
}[];
|
||||
recentTransactions: unknown[];
|
||||
}
|
||||
|
||||
interface CategoryBreakdownResponse {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
type: string;
|
||||
total: number;
|
||||
categories: {
|
||||
categoryId: string | null;
|
||||
name: string;
|
||||
color: string | null;
|
||||
icon: string | null;
|
||||
amount: number;
|
||||
count: number;
|
||||
percentage: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface TrendsResponse {
|
||||
months: number;
|
||||
data: {
|
||||
year: number;
|
||||
month: number;
|
||||
income: number;
|
||||
expense: number;
|
||||
net: number;
|
||||
}[];
|
||||
averages: {
|
||||
income: number;
|
||||
expense: number;
|
||||
net: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface CashFlowResponse {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
startingBalance: number;
|
||||
endingBalance: number;
|
||||
data: {
|
||||
date: string;
|
||||
balance: number;
|
||||
income: number;
|
||||
expense: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
export const reportsApi = {
|
||||
getDashboard: () => apiClient.get<Dashboard>('/reports/dashboard'),
|
||||
|
||||
getMonthlySummary: (year?: number, month?: number) => {
|
||||
const params = new URLSearchParams();
|
||||
if (year) params.append('year', String(year));
|
||||
if (month) params.append('month', String(month));
|
||||
const query = params.toString();
|
||||
return apiClient.get<MonthlySummary>(`/reports/monthly-summary${query ? `?${query}` : ''}`);
|
||||
},
|
||||
|
||||
getCategoryBreakdown: (startDate: string, endDate: string, type?: 'income' | 'expense') => {
|
||||
const params = new URLSearchParams({ startDate, endDate });
|
||||
if (type) params.append('type', type);
|
||||
return apiClient.get<CategoryBreakdownResponse>(`/reports/category-breakdown?${params}`);
|
||||
},
|
||||
|
||||
getTrends: (months = 6) => apiClient.get<TrendsResponse>(`/reports/trends?months=${months}`),
|
||||
|
||||
getCashFlow: (startDate: string, endDate: string) =>
|
||||
apiClient.get<CashFlowResponse>(`/reports/cash-flow?startDate=${startDate}&endDate=${endDate}`),
|
||||
};
|
||||
8
apps-archived/finance/apps/web/src/lib/api/settings.ts
Normal file
8
apps-archived/finance/apps/web/src/lib/api/settings.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { apiClient } from './client';
|
||||
import type { UserSettings, UpdateUserSettingsInput } from '@finance/shared';
|
||||
|
||||
export const settingsApi = {
|
||||
get: () => apiClient.get<UserSettings>('/settings'),
|
||||
|
||||
update: (data: UpdateUserSettingsInput) => apiClient.put<UserSettings>('/settings', data),
|
||||
};
|
||||
49
apps-archived/finance/apps/web/src/lib/api/transactions.ts
Normal file
49
apps-archived/finance/apps/web/src/lib/api/transactions.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { apiClient } from './client';
|
||||
import type {
|
||||
Transaction,
|
||||
CreateTransactionInput,
|
||||
UpdateTransactionInput,
|
||||
TransactionFilters,
|
||||
} from '@finance/shared';
|
||||
|
||||
interface PaginatedTransactions {
|
||||
data: Transaction[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export const transactionsApi = {
|
||||
getAll: (filters?: TransactionFilters) => {
|
||||
const params = new URLSearchParams();
|
||||
if (filters) {
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
params.append(key, String(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
const query = params.toString();
|
||||
return apiClient.get<PaginatedTransactions>(`/transactions${query ? `?${query}` : ''}`);
|
||||
},
|
||||
|
||||
getRecent: (limit = 10) => apiClient.get<Transaction[]>(`/transactions/recent?limit=${limit}`),
|
||||
|
||||
getSummary: (startDate: string, endDate: string) =>
|
||||
apiClient.get<{
|
||||
income: number;
|
||||
expense: number;
|
||||
net: number;
|
||||
incomeCount: number;
|
||||
expenseCount: number;
|
||||
}>(`/transactions/summary?startDate=${startDate}&endDate=${endDate}`),
|
||||
|
||||
getOne: (id: string) => apiClient.get<Transaction>(`/transactions/${id}`),
|
||||
|
||||
create: (data: CreateTransactionInput) => apiClient.post<Transaction>('/transactions', data),
|
||||
|
||||
update: (id: string, data: UpdateTransactionInput) =>
|
||||
apiClient.put<Transaction>(`/transactions/${id}`, data),
|
||||
|
||||
delete: (id: string) => apiClient.delete<{ success: boolean }>(`/transactions/${id}`),
|
||||
};
|
||||
15
apps-archived/finance/apps/web/src/lib/api/transfers.ts
Normal file
15
apps-archived/finance/apps/web/src/lib/api/transfers.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { apiClient } from './client';
|
||||
import type { Transfer, CreateTransferInput, UpdateTransferInput } from '@finance/shared';
|
||||
|
||||
export const transfersApi = {
|
||||
getAll: () => apiClient.get<Transfer[]>('/transfers'),
|
||||
|
||||
getOne: (id: string) => apiClient.get<Transfer>(`/transfers/${id}`),
|
||||
|
||||
create: (data: CreateTransferInput) => apiClient.post<Transfer>('/transfers', data),
|
||||
|
||||
update: (id: string, data: UpdateTransferInput) =>
|
||||
apiClient.put<Transfer>(`/transfers/${id}`, data),
|
||||
|
||||
delete: (id: string) => apiClient.delete<{ success: boolean }>(`/transfers/${id}`),
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue