Vue Composables
MYMO dùng 5 composables để quản lý state và business logic phía frontend. Tất cả composables dùng singleton pattern - state ở module scope, share giữa mọi components.
ts
// Singleton pattern
const config = ref<UserConfig | null>(null) // module-level
export function useRunway() {
// Mọi component gọi useRunway() đều share cùng config ref
return { config, ... }
}useAuth()
Authentication và session management.
State:
| Ref | Type | Mô tả |
|---|---|---|
authenticated | Ref<boolean> | Trạng thái đăng nhập |
userEmail | Ref<string> | Email user hiện tại |
Methods:
| Method | Signature | Mô tả |
|---|---|---|
login | (licenseKey: string) => Promise<void> | Đăng nhập bằng license key |
checkAuth | () => boolean | Kiểm tra token còn valid |
logout | () => void | Xóa token, reset state |
useRunway()
Config management, runway calculations, currency formatting.
State:
| Ref | Type | Mô tả |
|---|---|---|
config | Ref<UserConfig | null> | Config hiện tại |
loading | Ref<boolean> | Đang load config |
Computed:
| Computed | Type | Mô tả |
|---|---|---|
hasCompletedOnboarding | boolean | Config tồn tại = đã onboard |
runwayDays | number | total_cash / daily_burn_rate |
doomDate | string | Ngày hết tiền (formatted) |
status | 'safe' | 'warning' | 'danger' | >= 180 safe, >= 90 warning, else danger |
currencySymbol | string | Ký hiệu tiền tệ |
Methods:
| Method | Signature | Mô tả |
|---|---|---|
loadConfig | () => Promise<void> | Load config từ server |
completeOnboarding | (recurring, oneTime, totalCash) => Promise<void> | Hoàn thành onboarding |
resetOnboarding | () => Promise<void> | Xóa config |
updateTotalCash | (delta: number) => Promise<void> | Cộng/trừ tài sản |
formatAmount | (n: number) => string | Format số tiền + currency |
setCurrency | (currency: string) => Promise<void> | Đổi đơn vị tiền |
amountToDays | (amount: number) => number | Tiền → ngày |
amountToHours | (amount: number) => number | Tiền → giờ |
useTransactions()
Transaction CRUD và queries.
State:
| Ref | Type | Mô tả |
|---|---|---|
transactions | Ref<Transaction[]> | Danh sách giao dịch |
Methods:
| Method | Signature | Mô tả |
|---|---|---|
loadTransactions | () => Promise<void> | Load 50 giao dịch gần nhất |
createTransaction | (amount, date, categoryId, note) => Promise<void> | Tạo giao dịch |
updateTransaction | (id, amount, date, categoryId, note) => Promise<void> | Cập nhật |
deleteTransaction | (id: number) => Promise<void> | Xóa |
getMonthTransactions | (year, month) => Promise<TransactionWithCategory[]> | Theo tháng |
getMonthTierTotals | (year, month) => Promise<{tier, total}[]> | Tổng tier/tháng |
useCategories()
Category CRUD.
State:
| Ref | Type | Mô tả |
|---|---|---|
categories | Ref<Category[]> | Danh sách danh mục |
Methods:
| Method | Signature | Mô tả |
|---|---|---|
loadCategories | () => Promise<void> | Load tất cả danh mục |
findByName | (name: string) => Category | null | Tìm theo tên (case-insensitive) |
createCategory | (name, tier) => Promise<number> | Tạo, trả về id |
standardizeCategories | () => Promise<void> | AI chuẩn hóa tên |
useRecurring()
Recurring expense management.
State:
| Ref | Type | Mô tả |
|---|---|---|
recurringExpenses | Ref<RecurringWithCategory[]> | Danh sách recurring |
Methods:
| Method | Signature | Mô tả |
|---|---|---|
loadRecurring | () => Promise<void> | Load recurring |
catchUpRecurring | () => Promise<void> | Tạo transactions cho quá hạn |
createRecurringExpense | (name, amount, frequency, dayOfMonth, categoryId) => Promise<void> | Tạo |
updateRecurringExpense | (id, fields) => Promise<void> | Cập nhật |
deleteRecurringExpense | (id: number) => Promise<void> | Xóa |
Cross-Composable Dependencies
useRecurringimportsuseRunway(one-way dependency)- Sau khi mutate data ở composable A ảnh hưởng composable B → reload cả hai
- Không tạo circular imports giữa composables (gây undefined exports)