Adds a new module for tracking user expenses. The module includes: - Configuration settings for the LNbits API endpoint and timeouts. - An ExpensesAPI service for fetching accounts and submitting expense entries. - A UI component for adding expenses, including account selection and form input. - Dependency injection for the ExpensesAPI service. This allows users to submit expense entries with account selection and reference data, which will be linked to their wallet.
225 lines
No EOL
6.3 KiB
TypeScript
225 lines
No EOL
6.3 KiB
TypeScript
import { createApp } from 'vue'
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
import { createPinia } from 'pinia'
|
|
// Core plugin system
|
|
import { pluginManager } from './core/plugin-manager'
|
|
import { eventBus } from './core/event-bus'
|
|
import { container } from './core/di-container'
|
|
|
|
// App configuration
|
|
import appConfig from './app.config'
|
|
|
|
// Base modules
|
|
import baseModule from './modules/base'
|
|
import nostrFeedModule from './modules/nostr-feed'
|
|
import chatModule from './modules/chat'
|
|
import eventsModule from './modules/events'
|
|
import marketModule from './modules/market'
|
|
import walletModule from './modules/wallet'
|
|
import expensesModule from './modules/expenses'
|
|
|
|
// Root component
|
|
import App from './App.vue'
|
|
|
|
// Styles
|
|
import './assets/index.css'
|
|
|
|
// Use existing i18n setup
|
|
import { i18n } from './i18n'
|
|
|
|
/**
|
|
* Initialize and start the modular application
|
|
*/
|
|
export async function createAppInstance() {
|
|
console.log('🚀 Starting modular application...')
|
|
|
|
// Create Vue app
|
|
const app = createApp(App)
|
|
|
|
// Collect all module routes automatically to avoid duplication
|
|
const moduleRoutes = [
|
|
// Extract routes from modules directly
|
|
...baseModule.routes || [],
|
|
...nostrFeedModule.routes || [],
|
|
...chatModule.routes || [],
|
|
...eventsModule.routes || [],
|
|
...marketModule.routes || [],
|
|
...walletModule.routes || [],
|
|
...expensesModule.routes || []
|
|
].filter(Boolean)
|
|
|
|
// Create router with all routes available immediately
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [
|
|
// Default routes
|
|
{
|
|
path: '/',
|
|
name: 'home',
|
|
component: () => import('./pages/Home.vue'),
|
|
meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/login',
|
|
name: 'login',
|
|
component: () => import('./pages/Login.vue'),
|
|
meta: { requiresAuth: false }
|
|
},
|
|
// Pre-register module routes
|
|
...moduleRoutes
|
|
]
|
|
})
|
|
|
|
// Use existing i18n setup
|
|
|
|
// Create Pinia store
|
|
const pinia = createPinia()
|
|
|
|
// Install core plugins
|
|
app.use(router)
|
|
app.use(pinia)
|
|
app.use(i18n)
|
|
|
|
// Initialize plugin manager
|
|
pluginManager.init(app, router)
|
|
|
|
// Register modules based on configuration
|
|
const moduleRegistrations = []
|
|
|
|
// Register base module first (required)
|
|
if (appConfig.modules.base.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(baseModule, appConfig.modules.base)
|
|
)
|
|
}
|
|
|
|
// Register nostr-feed module
|
|
if (appConfig.modules['nostr-feed'].enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(nostrFeedModule, appConfig.modules['nostr-feed'])
|
|
)
|
|
}
|
|
|
|
// Register chat module
|
|
if (appConfig.modules.chat.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(chatModule, appConfig.modules.chat)
|
|
)
|
|
}
|
|
|
|
// Register events module
|
|
if (appConfig.modules.events.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(eventsModule, appConfig.modules.events)
|
|
)
|
|
}
|
|
|
|
// Register market module
|
|
if (appConfig.modules.market.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(marketModule, appConfig.modules.market)
|
|
)
|
|
}
|
|
|
|
// Register wallet module
|
|
if (appConfig.modules.wallet?.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(walletModule, appConfig.modules.wallet)
|
|
)
|
|
}
|
|
|
|
// Register expenses module
|
|
if (appConfig.modules.expenses?.enabled) {
|
|
moduleRegistrations.push(
|
|
pluginManager.register(expensesModule, appConfig.modules.expenses)
|
|
)
|
|
}
|
|
|
|
// Wait for all modules to register
|
|
await Promise.all(moduleRegistrations)
|
|
|
|
// Install all enabled modules
|
|
await pluginManager.installAll()
|
|
|
|
// Initialize auth before setting up router guards
|
|
const { auth } = await import('@/composables/useAuthService')
|
|
await auth.initialize()
|
|
console.log('Auth initialized, isAuthenticated:', auth.isAuthenticated.value)
|
|
|
|
// Set up auth guard
|
|
router.beforeEach(async (to, _from, next) => {
|
|
// Default to requiring auth unless explicitly set to false
|
|
const requiresAuth = to.meta.requiresAuth !== false
|
|
|
|
if (requiresAuth && !auth.isAuthenticated.value) {
|
|
console.log(`Auth guard: User not authenticated, redirecting from ${to.path} to login`)
|
|
next('/login')
|
|
} else if (to.path === '/login' && auth.isAuthenticated.value) {
|
|
console.log('Auth guard: User already authenticated, redirecting to home')
|
|
next('/')
|
|
} else {
|
|
console.log(`Auth guard: Allowing navigation to ${to.path} (requiresAuth: ${requiresAuth}, authenticated: ${auth.isAuthenticated.value})`)
|
|
next()
|
|
}
|
|
})
|
|
|
|
// Check initial route and redirect if needed
|
|
if (!auth.isAuthenticated.value) {
|
|
const currentRoute = router.currentRoute.value
|
|
const requiresAuth = currentRoute.meta.requiresAuth !== false
|
|
if (requiresAuth) {
|
|
console.log('Initial route requires auth but user not authenticated, redirecting to login')
|
|
await router.push('/login')
|
|
}
|
|
}
|
|
|
|
// Global error handling
|
|
app.config.errorHandler = (err, _vm, info) => {
|
|
console.error('Global error:', err, info)
|
|
eventBus.emit('app:error', { error: err, info }, 'app')
|
|
}
|
|
|
|
// Development helpers
|
|
if (appConfig.features.developmentMode) {
|
|
// Expose debugging helpers globally
|
|
;(window as any).__pluginManager = pluginManager
|
|
;(window as any).__eventBus = eventBus
|
|
;(window as any).__container = container
|
|
|
|
console.log('🔧 Development mode enabled')
|
|
console.log('Available globals: __pluginManager, __eventBus, __container')
|
|
}
|
|
|
|
console.log('✅ Application initialized successfully')
|
|
|
|
return { app, router }
|
|
}
|
|
|
|
/**
|
|
* Start the application
|
|
*/
|
|
export async function startApp() {
|
|
try {
|
|
const { app } = await createAppInstance()
|
|
|
|
// Mount the app
|
|
app.mount('#app')
|
|
|
|
console.log('🎉 Application started!')
|
|
|
|
// Emit app started event
|
|
eventBus.emit('app:started', {}, 'app')
|
|
|
|
} catch (error) {
|
|
console.error('💥 Failed to start application:', error)
|
|
|
|
// Show error to user
|
|
document.getElementById('app')!.innerHTML = `
|
|
<div style="padding: 20px; text-align: center; color: red;">
|
|
<h1>Application Failed to Start</h1>
|
|
<p>${error instanceof Error ? error.message : 'Unknown error'}</p>
|
|
<p>Please refresh the page or contact support.</p>
|
|
</div>
|
|
`
|
|
}
|
|
} |