This refactors the data handlers into a more standard/understood model-like architecture, to prepare for a new, more robust config system. It also fixes a problem with creating new Notes and uploading new Photos via the web interface (related to #58). Finally, it speeds up docker builds by sending in less files, which aren't necessary or will be built anyway. This is all in preparation to allow building #13 more robustly.
74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
import { Handlers, PageProps } from 'fresh/server.ts';
|
|
|
|
import { Budget, Expense, FreshContextState, SupportedCurrencySymbol } from '/lib/types.ts';
|
|
import { isAppEnabled } from '/lib/config.ts';
|
|
import { BudgetModel, ExpenseModel, generateMonthlyBudgetsAndExpenses } from '/lib/models/expenses.ts';
|
|
import ExpensesWrapper from '/islands/expenses/ExpensesWrapper.tsx';
|
|
|
|
interface Data {
|
|
userBudgets: Budget[];
|
|
userExpenses: Expense[];
|
|
initialMonth: string;
|
|
currency: SupportedCurrencySymbol;
|
|
}
|
|
|
|
export const handler: Handlers<Data, FreshContextState> = {
|
|
async GET(request, context) {
|
|
if (!context.state.user) {
|
|
return new Response('Redirect', { status: 303, headers: { 'Location': `/login` } });
|
|
}
|
|
|
|
if (!isAppEnabled('expenses')) {
|
|
return new Response('Redirect', { status: 303, headers: { 'Location': `/files` } });
|
|
}
|
|
|
|
const searchParams = new URL(request.url).searchParams;
|
|
|
|
let initialMonth = searchParams.get('month') || new Date().toISOString().substring(0, 7);
|
|
|
|
const currentMonth = new Date().toISOString().substring(0, 7);
|
|
const nextMonth = new Date(new Date(currentMonth).setUTCMonth(new Date(currentMonth).getUTCMonth() + 1))
|
|
.toISOString()
|
|
.substring(0, 7);
|
|
|
|
// Send invalid months (format) back to current month
|
|
if (!initialMonth.match(/^\d{4}-\d{2}$/)) {
|
|
initialMonth = currentMonth;
|
|
}
|
|
|
|
// Reset to next month if the selected month is too far in the future
|
|
if (initialMonth > nextMonth) {
|
|
initialMonth = nextMonth;
|
|
}
|
|
|
|
let userBudgets = await BudgetModel.list(context.state.user.id, initialMonth);
|
|
|
|
let userExpenses = await ExpenseModel.list(context.state.user.id, initialMonth);
|
|
|
|
// If there are no budgets or expenses, and the selected month is in the future, generate the month's budgets and expenses
|
|
if (userBudgets.length === 0 && userExpenses.length === 0 && initialMonth >= currentMonth) {
|
|
await generateMonthlyBudgetsAndExpenses(context.state.user.id, initialMonth);
|
|
|
|
userBudgets = await BudgetModel.list(context.state.user.id, initialMonth);
|
|
userExpenses = await ExpenseModel.list(context.state.user.id, initialMonth);
|
|
}
|
|
|
|
const currency = context.state.user.extra.expenses_currency || '$';
|
|
|
|
return await context.render({ userBudgets, userExpenses, initialMonth, currency });
|
|
},
|
|
};
|
|
|
|
export default function ExpensesPage({ data }: PageProps<Data, FreshContextState>) {
|
|
return (
|
|
<main>
|
|
<ExpensesWrapper
|
|
initialBudgets={data.userBudgets}
|
|
initialExpenses={data.userExpenses}
|
|
initialMonth={data.initialMonth}
|
|
currency={data.currency}
|
|
/>
|
|
</main>
|
|
);
|
|
}
|