- Fix async/await usage in background fetch handler - Fix Core Data metadata access errors - Replace SQLITE_TRANSIENT with nil for Swift compatibility - Fix PermissionStatus interface and type casts in test app - Add iOS setup documentation to BUILDING.md - Update iOS sync workflow to handle Podfile regeneration Resolves all iOS compilation errors and improves test app setup process.
718 lines
25 KiB
Vue
718 lines
25 KiB
Vue
<!--
|
||
/**
|
||
* Home View - Main Dashboard
|
||
*
|
||
* Platform-neutral home view with quick actions and plugin diagnostics
|
||
*
|
||
* @author Matthew Raymer
|
||
* @version 1.0.0
|
||
*/
|
||
-->
|
||
|
||
<template>
|
||
<div class="home-view">
|
||
<!-- Welcome Section -->
|
||
<div class="welcome-section">
|
||
<h1 class="welcome-title">
|
||
🔔 Daily Notification Test
|
||
</h1>
|
||
<p class="welcome-subtitle">
|
||
Vue 3 + Capacitor + DailyNotification Plugin
|
||
</p>
|
||
<div class="platform-info">
|
||
<span class="platform-badge" :class="platformClass">
|
||
{{ platformName }}
|
||
</span>
|
||
<span class="status-badge" :class="statusClass">
|
||
{{ statusText }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Quick Actions -->
|
||
<div class="quick-actions">
|
||
<h2 class="section-title">Quick Actions</h2>
|
||
<div class="action-grid">
|
||
<ActionCard
|
||
icon="📅"
|
||
title="Schedule Notification"
|
||
description="Schedule a new daily notification"
|
||
@click="navigateToSchedule"
|
||
:loading="isScheduling"
|
||
/>
|
||
<ActionCard
|
||
icon="📊"
|
||
title="Check Status"
|
||
description="View notification system status"
|
||
@click="checkSystemStatus"
|
||
:loading="isCheckingStatus"
|
||
/>
|
||
<ActionCard
|
||
icon="🔐"
|
||
title="Request Permissions"
|
||
description="Check and request notification permissions"
|
||
@click="checkAndRequestPermissions"
|
||
:loading="isRequestingPermissions"
|
||
/>
|
||
<ActionCard
|
||
icon="🔔"
|
||
title="View Notifications"
|
||
description="Manage scheduled notifications"
|
||
@click="navigateToNotifications"
|
||
/>
|
||
<ActionCard
|
||
icon="📋"
|
||
title="View History"
|
||
description="Check notification history"
|
||
@click="navigateToHistory"
|
||
/>
|
||
<ActionCard
|
||
icon="📜"
|
||
title="View Logs"
|
||
description="Check system logs and debug info"
|
||
@click="navigateToLogs"
|
||
/>
|
||
<ActionCard
|
||
icon="⚙️"
|
||
title="Settings"
|
||
description="Configure app preferences"
|
||
@click="navigateToSettings"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- System Status -->
|
||
<div class="system-status">
|
||
<h2 class="section-title">System Status</h2>
|
||
<div class="status-grid">
|
||
<StatusCard
|
||
v-for="item in systemStatus"
|
||
:key="item.label"
|
||
:title="item.label"
|
||
:status="getStatusType(item.status)"
|
||
:value="item.value"
|
||
:description="getStatusDescription(item.label)"
|
||
@refresh="refreshSystemStatus"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Diagnostic Actions -->
|
||
<div class="section">
|
||
<h2 class="section-title">🔧 Diagnostics</h2>
|
||
<ActionCard
|
||
title="Plugin Diagnostics"
|
||
description="Check plugin loading and availability"
|
||
button-text="Run Diagnostics"
|
||
@click="runPluginDiagnostics"
|
||
/>
|
||
<ActionCard
|
||
title="View Console Logs"
|
||
description="Open browser console for detailed logs"
|
||
button-text="Open Console"
|
||
@click="openConsole"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { useAppStore } from '@/stores/app'
|
||
import ActionCard from '@/components/cards/ActionCard.vue'
|
||
import StatusCard from '@/components/cards/StatusCard.vue'
|
||
import { Capacitor } from '@capacitor/core'
|
||
import { DailyNotification } from '@timesafari/daily-notification-plugin'
|
||
import { TEST_USER_ZERO_CONFIG, generateEndorserJWT } from '@/config/test-user-zero'
|
||
import { logger } from '@/lib/logger'
|
||
|
||
const router = useRouter()
|
||
const appStore = useAppStore()
|
||
|
||
const isScheduling = ref(false)
|
||
const isCheckingStatus = ref(false)
|
||
const isRequestingPermissions = ref(false)
|
||
const nativeFetcherConfigured = ref(false)
|
||
|
||
const platformName = computed(() => {
|
||
const platform = appStore.platform
|
||
return platform.charAt(0).toUpperCase() + platform.slice(1)
|
||
})
|
||
|
||
const platformClass = computed(() => `platform-${appStore.platform}`)
|
||
|
||
const statusClass = computed(() => {
|
||
const status = appStore.notificationStatus
|
||
if (!status) return 'unknown'
|
||
if (status.canScheduleNow) return 'ready'
|
||
return 'not-ready'
|
||
})
|
||
|
||
const statusText = computed(() => {
|
||
const status = appStore.notificationStatus
|
||
if (!status) return 'Unknown'
|
||
if (status.canScheduleNow) return 'Ready'
|
||
return 'Not Ready'
|
||
})
|
||
|
||
const systemStatus = computed(() => {
|
||
const status = appStore.notificationStatus
|
||
if (!status) {
|
||
return [
|
||
{ label: 'Platform', value: platformName.value, status: 'info' },
|
||
{ label: 'Plugin', value: 'Not Available', status: 'error' }
|
||
]
|
||
}
|
||
|
||
return [
|
||
{ label: 'Platform', value: platformName.value, status: 'info' },
|
||
{ label: 'Plugin', value: 'Available', status: 'success' },
|
||
{ label: 'Permissions', value: status.postNotificationsGranted ? 'Granted' : 'Not Granted', status: status.postNotificationsGranted ? 'success' : 'warning' },
|
||
{ label: 'Can Schedule', value: status.canScheduleNow ? 'Yes' : 'No', status: status.canScheduleNow ? 'success' : 'warning' },
|
||
{ label: 'Next Scheduled', value: status.nextScheduledAt ? new Date(status.nextScheduledAt).toLocaleTimeString() : 'None', status: 'info' }
|
||
]
|
||
})
|
||
|
||
const navigateToSchedule = (): void => {
|
||
console.log('🔄 CLICK: Navigate to Schedule')
|
||
router.push('/schedule')
|
||
}
|
||
|
||
const navigateToNotifications = (): void => {
|
||
console.log('🔄 CLICK: Navigate to Notifications')
|
||
router.push('/notifications')
|
||
}
|
||
|
||
const navigateToHistory = (): void => {
|
||
console.log('🔄 CLICK: Navigate to History')
|
||
router.push('/history')
|
||
}
|
||
|
||
const navigateToLogs = (): void => {
|
||
console.log('🔄 CLICK: Navigate to Logs')
|
||
router.push('/logs')
|
||
}
|
||
|
||
const navigateToSettings = (): void => {
|
||
console.log('🔄 CLICK: Navigate to Settings')
|
||
router.push('/settings')
|
||
}
|
||
|
||
const checkSystemStatus = async (): Promise<void> => {
|
||
console.log('🔄 CLICK: Check System Status')
|
||
isCheckingStatus.value = true
|
||
|
||
try {
|
||
console.log('🔧 Checking system status...')
|
||
|
||
// Use the same detection logic as runPluginDiagnostics
|
||
const { Capacitor } = await import('@capacitor/core')
|
||
const platform = Capacitor.getPlatform()
|
||
const isNative = platform !== 'web'
|
||
|
||
if (isNative) {
|
||
console.log('🔧 Native platform detected, checking plugin availability...')
|
||
|
||
// Check if DailyNotification plugin is available
|
||
const { DailyNotification } = await import('@timesafari/daily-notification-plugin')
|
||
const plugin = DailyNotification
|
||
const isPluginAvailable = plugin && typeof plugin.getNotificationStatus === 'function'
|
||
console.log('🔧 DailyNotification plugin check:', isPluginAvailable ? 'Available' : 'Not Available')
|
||
console.log('🔧 Plugin object:', plugin)
|
||
|
||
if (plugin) {
|
||
console.log('✅ Plugin available, checking status...')
|
||
try {
|
||
const status = await plugin.getNotificationStatus()
|
||
// Use checkPermissionStatus() which is the correct method name for iOS
|
||
const permissions = await plugin.checkPermissionStatus()
|
||
const exactAlarmStatus = await plugin.getExactAlarmStatus()
|
||
|
||
console.log('📊 Plugin status object:', status)
|
||
console.log('📊 Status values:')
|
||
console.log(' - isEnabled:', status.isEnabled)
|
||
console.log(' - isScheduled:', status.isScheduled)
|
||
console.log(' - lastNotificationTime:', status.lastNotificationTime)
|
||
console.log(' - nextNotificationTime:', status.nextNotificationTime)
|
||
console.log(' - pending:', status.pending)
|
||
console.log(' - error:', status.error)
|
||
|
||
console.log('📊 Plugin permissions:', permissions)
|
||
console.log('📊 Permissions details:')
|
||
console.log(' - notificationsEnabled:', permissions.notificationsEnabled)
|
||
console.log(' - exactAlarmEnabled:', permissions.exactAlarmEnabled)
|
||
console.log(' - wakeLockEnabled:', permissions.wakeLockEnabled)
|
||
console.log(' - allPermissionsGranted:', permissions.allPermissionsGranted)
|
||
console.log('📊 Exact alarm status:', exactAlarmStatus)
|
||
|
||
// Map plugin response to app store format
|
||
// checkPermissionStatus() returns PermissionStatusResult with boolean flags
|
||
const mappedStatus = {
|
||
canScheduleNow: status.isEnabled ?? false,
|
||
postNotificationsGranted: permissions.notificationsEnabled ?? false,
|
||
channelEnabled: true, // Default for now
|
||
channelImportance: 3, // Default for now
|
||
channelId: 'daily-notifications',
|
||
exactAlarmsGranted: exactAlarmStatus.enabled,
|
||
exactAlarmsSupported: exactAlarmStatus.supported,
|
||
androidVersion: 33, // Default for now
|
||
nextScheduledAt: typeof status.nextNotificationTime === 'number'
|
||
? status.nextNotificationTime
|
||
: await status.nextNotificationTime
|
||
}
|
||
|
||
// Update the app store status - even if permissions aren't granted
|
||
appStore.setNotificationStatus(mappedStatus)
|
||
console.log('✅ System status updated successfully')
|
||
|
||
// Log permission status for debugging
|
||
if (!mappedStatus.postNotificationsGranted) {
|
||
console.warn('⚠️ Notification permissions not granted - user needs to enable in settings')
|
||
|
||
// Only request permissions if not already requesting
|
||
if (!isRequestingPermissions.value) {
|
||
console.log('🔧 Testing permission request...')
|
||
isRequestingPermissions.value = true
|
||
|
||
// Enhanced debugging for permission request
|
||
console.log('🔍 DEBUG: Plugin object:', plugin)
|
||
console.log('🔍 DEBUG: Plugin type:', typeof plugin)
|
||
console.log('🔍 DEBUG: requestPermissions method:', typeof plugin.requestPermissions)
|
||
console.log('🔍 DEBUG: Available methods:', Object.getOwnPropertyNames(plugin))
|
||
|
||
try {
|
||
console.log('🔍 DEBUG: About to call plugin.requestPermissions()')
|
||
const result = await plugin.requestPermissions()
|
||
console.log('✅ Permission request completed, result:', result)
|
||
|
||
// After permission request, refresh the status
|
||
console.log('🔄 Refreshing status after permission request...')
|
||
await checkSystemStatus()
|
||
} catch (permError) {
|
||
console.error('❌ Permission request failed:', permError)
|
||
console.error('❌ Error details:', {
|
||
name: permError.name,
|
||
message: permError.message,
|
||
stack: permError.stack
|
||
})
|
||
} finally {
|
||
isRequestingPermissions.value = false
|
||
}
|
||
} else {
|
||
console.log('⏳ Permission request already in progress, skipping...')
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ Plugin status check failed:', error)
|
||
// Keep existing status or set error state
|
||
}
|
||
} else {
|
||
console.warn('⚠️ DailyNotification plugin not available')
|
||
// Reset to error state
|
||
appStore.setNotificationStatus(null)
|
||
}
|
||
} else {
|
||
console.log('🌐 Web platform - plugin not available')
|
||
appStore.setNotificationStatus(null)
|
||
}
|
||
|
||
console.log('🔧 System status check completed')
|
||
} catch (error) {
|
||
console.error('❌ System status check failed:', error)
|
||
} finally {
|
||
isCheckingStatus.value = false
|
||
}
|
||
}
|
||
|
||
const getStatusType = (status: string): 'success' | 'warning' | 'error' | 'info' => {
|
||
switch (status) {
|
||
case 'success':
|
||
case 'warning':
|
||
case 'error':
|
||
case 'info':
|
||
return status
|
||
default:
|
||
return 'info'
|
||
}
|
||
}
|
||
|
||
const getStatusDescription = (label: string): string => {
|
||
switch (label) {
|
||
case 'Platform':
|
||
return 'Current platform information'
|
||
case 'Plugin':
|
||
return 'DailyNotification plugin availability'
|
||
case 'Permissions':
|
||
return 'Notification permission status'
|
||
case 'Can Schedule':
|
||
return 'Ready to schedule notifications'
|
||
case 'Next Scheduled':
|
||
return 'Next scheduled notification time'
|
||
default:
|
||
return 'System status information'
|
||
}
|
||
}
|
||
|
||
const refreshSystemStatus = async (): Promise<void> => {
|
||
console.log('🔄 CLICK: Refresh System Status')
|
||
await checkSystemStatus()
|
||
}
|
||
|
||
/**
|
||
* Check permissions and request if needed (Android pattern)
|
||
* 1. Check permission status first
|
||
* 2. If not granted, show system dialog
|
||
* 3. Refresh status after request
|
||
*/
|
||
const checkAndRequestPermissions = async (): Promise<void> => {
|
||
console.log('🔐 CLICK: Check and Request Permissions')
|
||
|
||
if (isRequestingPermissions.value) {
|
||
console.log('⏳ Permission request already in progress')
|
||
return
|
||
}
|
||
|
||
isRequestingPermissions.value = true
|
||
|
||
try {
|
||
const { DailyNotification } = await import('@timesafari/daily-notification-plugin')
|
||
const plugin = DailyNotification
|
||
|
||
if (!plugin) {
|
||
console.error('❌ DailyNotification plugin not available')
|
||
return
|
||
}
|
||
|
||
// Step 1: Check permission status first (Android pattern)
|
||
console.log('🔍 Step 1: Checking current permission status...')
|
||
const permissionStatus = await plugin.checkPermissionStatus()
|
||
|
||
console.log('📊 Permission status:', {
|
||
notificationsEnabled: permissionStatus.notificationsEnabled,
|
||
exactAlarmEnabled: permissionStatus.exactAlarmEnabled,
|
||
allPermissionsGranted: permissionStatus.allPermissionsGranted
|
||
})
|
||
|
||
// Step 2: If not granted, show system dialog
|
||
if (!permissionStatus.notificationsEnabled) {
|
||
console.log('⚠️ Permissions not granted - showing system dialog...')
|
||
console.log('📱 iOS will show native permission dialog now...')
|
||
|
||
// Request permissions - this will show the iOS system dialog
|
||
// Try requestNotificationPermissions first (iOS), fallback to requestPermissions
|
||
if (typeof (plugin as any).requestNotificationPermissions === 'function') {
|
||
await (plugin as { requestNotificationPermissions: () => Promise<any> }).requestNotificationPermissions()
|
||
} else if (typeof (plugin as any).requestPermissions === 'function') {
|
||
await (plugin as { requestPermissions: () => Promise<any> }).requestPermissions()
|
||
} else {
|
||
throw new Error('Permission request method not available')
|
||
}
|
||
|
||
console.log('✅ Permission request completed')
|
||
|
||
// Step 3: Refresh status after request
|
||
console.log('🔄 Refreshing status after permission request...')
|
||
await new Promise(resolve => setTimeout(resolve, 1000)) // Wait 1 second for system to update
|
||
await checkSystemStatus()
|
||
} else {
|
||
console.log('✅ Permissions already granted - no dialog needed')
|
||
// Still refresh status to show current state
|
||
await checkSystemStatus()
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('❌ Permission check/request failed:', error)
|
||
console.error('❌ Error details:', {
|
||
name: (error as Error).name,
|
||
message: (error as Error).message,
|
||
stack: (error as Error).stack
|
||
})
|
||
} finally {
|
||
isRequestingPermissions.value = false
|
||
}
|
||
}
|
||
|
||
const runPluginDiagnostics = async (): Promise<void> => {
|
||
console.log('🔄 CLICK: Plugin Diagnostics - METHOD CALLED!')
|
||
console.log('🔄 FUNCTION START: runPluginDiagnostics called at', new Date().toISOString())
|
||
try {
|
||
console.log('🔧 Running plugin diagnostics...')
|
||
console.log('🔧 BUTTON CLICKED - METHOD CALLED!')
|
||
|
||
// Check if we're on a native platform
|
||
const { Capacitor } = await import('@capacitor/core')
|
||
const platform = Capacitor.getPlatform()
|
||
const isNative = Capacitor.isNativePlatform()
|
||
|
||
console.log('📱 Platform:', platform)
|
||
console.log('🔧 Native Platform:', isNative)
|
||
|
||
if (isNative) {
|
||
// Use proper plugin import
|
||
const { DailyNotification } = await import('@timesafari/daily-notification-plugin')
|
||
const plugin = DailyNotification
|
||
const isPluginAvailable = plugin && typeof plugin.getNotificationStatus === 'function'
|
||
|
||
console.log('🔍 Plugin detection debug:')
|
||
console.log(' - DailyNotification plugin:', isPluginAvailable ? 'Available' : 'Not Available')
|
||
console.log(' - Plugin object:', plugin)
|
||
|
||
if (plugin) {
|
||
console.log('✅ DailyNotification plugin available')
|
||
|
||
// Get all available plugins
|
||
const allPlugins = Object.keys((window as Window & { Capacitor?: { Plugins?: Record<string, unknown> } }).Capacitor?.Plugins || {})
|
||
console.log('📋 All available plugins:', allPlugins)
|
||
|
||
// Test the checkStatus method
|
||
try {
|
||
const status = await plugin.getNotificationStatus()
|
||
console.log('📊 Plugin status check result:', status)
|
||
|
||
// Create detailed plugin report
|
||
const pluginReport = {
|
||
platform: platform,
|
||
nativePlatform: isNative,
|
||
dailyNotificationAvailable: true,
|
||
allAvailablePlugins: allPlugins,
|
||
dailyNotificationStatus: status,
|
||
capacitorVersion: (window as Window & { Capacitor?: { getPlatform?: () => string } }).Capacitor?.getPlatform ? 'Available' : 'Unknown',
|
||
webViewInfo: {
|
||
userAgent: navigator.userAgent,
|
||
platform: navigator.platform
|
||
}
|
||
}
|
||
|
||
alert(`✅ Plugin Diagnostics Complete!\n\n` +
|
||
`Platform: ${platform}\n` +
|
||
`Native Platform: ${isNative}\n` +
|
||
`DailyNotification Plugin: Available\n` +
|
||
`All Plugins (${allPlugins.length}): ${allPlugins.join(', ')}\n\n` +
|
||
`DailyNotification Status:\n${JSON.stringify(status, null, 2)}\n\n` +
|
||
`Full Report:\n${JSON.stringify(pluginReport, null, 2)}`)
|
||
} catch (error) {
|
||
console.error('❌ Plugin status check failed:', error)
|
||
alert(`⚠️ Plugin Diagnostics Complete!\n\nPlatform: ${platform}\nPlugin Available: Yes\nStatus Check Failed: ${error}\n\nAll Available Plugins: ${allPlugins.join(', ')}`)
|
||
}
|
||
} else {
|
||
console.warn('⚠️ DailyNotification plugin not available')
|
||
const allPlugins = Object.keys((window as Window & { Capacitor?: { Plugins?: Record<string, unknown> } }).Capacitor?.Plugins || {})
|
||
alert(`❌ Plugin Diagnostics Complete!\n\nPlatform: ${platform}\nDailyNotification Plugin: Not Available\n\nAll Available Plugins (${allPlugins.length}):\n${allPlugins.join(', ')}\n\nCapacitor Plugins Object:\n${JSON.stringify((window as Window & { Capacitor?: { Plugins?: Record<string, unknown> } }).Capacitor?.Plugins || {}, null, 2)}`)
|
||
}
|
||
} else {
|
||
console.log('🌐 Running in web mode - plugin not available')
|
||
alert(`ℹ️ Plugin Diagnostics Complete!\n\nPlatform: ${platform}\nNative Platform: No\nPlugin Available: No (Web mode)`)
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ Plugin diagnostics failed:', error)
|
||
alert(`❌ Plugin Diagnostics Failed!\n\nError: ${error}`)
|
||
}
|
||
}
|
||
|
||
const openConsole = (): void => {
|
||
console.log('🔄 CLICK: Open Console - METHOD CALLED!')
|
||
console.log('📖 Console opened - check browser developer tools for detailed logs')
|
||
alert('📖 Console Logs\n\nOpen your browser\'s Developer Tools (F12) and check the Console tab for detailed diagnostic information.')
|
||
}
|
||
|
||
// Configure native fetcher for background workers
|
||
const configureNativeFetcher = async (): Promise<void> => {
|
||
// Only configure once
|
||
if (nativeFetcherConfigured.value) {
|
||
console.log('⏭️ HomeView: Native fetcher already configured, skipping')
|
||
return
|
||
}
|
||
|
||
// Only configure on native platforms
|
||
if (!Capacitor.isNativePlatform()) {
|
||
console.log('⏭️ HomeView: Web platform - skipping native fetcher configuration')
|
||
return
|
||
}
|
||
|
||
try {
|
||
console.log('🚀 HomeView: Starting native fetcher configuration...')
|
||
console.log('👤 HomeView: Using User Zero identity:', TEST_USER_ZERO_CONFIG.identity.name)
|
||
console.log('🔑 HomeView: User Zero DID:', TEST_USER_ZERO_CONFIG.identity.did)
|
||
logger.info('Configuring native fetcher from HomeView using User Zero identity...')
|
||
|
||
// Get API server URL
|
||
const apiBaseUrl = TEST_USER_ZERO_CONFIG.getApiServerUrl()
|
||
console.log('🔧 HomeView: API Base URL:', apiBaseUrl)
|
||
console.log('🔧 HomeView: Server Mode:', TEST_USER_ZERO_CONFIG.api.serverMode)
|
||
|
||
// Skip configuration if in mock mode
|
||
if (TEST_USER_ZERO_CONFIG.api.serverMode === 'mock') {
|
||
console.log('⏭️ HomeView: Mock mode - skipping configuration')
|
||
logger.warn('Mock mode enabled - native fetcher will not be configured')
|
||
nativeFetcherConfigured.value = true // Mark as "configured" to prevent retries
|
||
return
|
||
}
|
||
|
||
console.log('🔧 HomeView: Generating ES256K JWT token for User Zero...')
|
||
// Generate JWT token for authentication using User Zero's DID and seed phrase
|
||
// This uses TEST_USER_ZERO_CONFIG.identity.did and TEST_USER_ZERO_CONFIG.identity.seedPhrase
|
||
const jwtToken = await generateEndorserJWT()
|
||
console.log('✅ HomeView: JWT token generated for User Zero, length:', jwtToken.length)
|
||
|
||
console.log('🔧 HomeView: Configuring native fetcher with User Zero credentials:', {
|
||
apiBaseUrl,
|
||
activeDid: TEST_USER_ZERO_CONFIG.identity.did,
|
||
userZeroName: TEST_USER_ZERO_CONFIG.identity.name,
|
||
jwtTokenLength: jwtToken.length
|
||
})
|
||
|
||
// Configure native fetcher with User Zero's credentials
|
||
// This passes User Zero's DID and JWT token (signed with User Zero's private key)
|
||
await DailyNotification.configureNativeFetcher({
|
||
apiBaseUrl: apiBaseUrl,
|
||
activeDid: TEST_USER_ZERO_CONFIG.identity.did, // User Zero's DID
|
||
jwtToken: jwtToken // JWT signed with User Zero's private key derived from seed phrase
|
||
})
|
||
|
||
console.log('✅ HomeView: Native fetcher configured successfully!')
|
||
logger.info('Native fetcher configured successfully', {
|
||
apiBaseUrl: apiBaseUrl.substring(0, 50) + '...',
|
||
activeDid: TEST_USER_ZERO_CONFIG.identity.did.substring(0, 30) + '...'
|
||
})
|
||
|
||
// Update starred plan IDs from config (non-blocking - if this fails, fetcher is still configured)
|
||
try {
|
||
console.log('🔧 HomeView: Updating starred plan IDs...')
|
||
const planIds = [...TEST_USER_ZERO_CONFIG.starredProjects.planIds]
|
||
console.log('🔧 HomeView: Plan IDs to update:', planIds.length, 'plans')
|
||
console.log('🔧 HomeView: Plan IDs array:', JSON.stringify(planIds))
|
||
|
||
const updateResult = await DailyNotification.updateStarredPlans({
|
||
planIds: planIds
|
||
})
|
||
|
||
console.log('✅ HomeView: Starred plans updated:', {
|
||
count: updateResult.planIdsCount,
|
||
updatedAt: new Date(updateResult.updatedAt).toISOString()
|
||
})
|
||
} catch (starredPlansError) {
|
||
// Non-critical error - native fetcher is already configured
|
||
console.warn('⚠️ HomeView: Failed to update starred plans (non-critical):', starredPlansError)
|
||
logger.warn('Starred plans update failed (native fetcher is still configured)', {
|
||
error: starredPlansError instanceof Error ? starredPlansError.message : String(starredPlansError)
|
||
})
|
||
}
|
||
|
||
// Mark as configured to prevent duplicate configuration
|
||
nativeFetcherConfigured.value = true
|
||
} catch (error) {
|
||
console.error('❌ HomeView: Failed to configure native fetcher:', error)
|
||
console.error('❌ HomeView: Error details:', error instanceof Error ? error.stack : String(error))
|
||
logger.error('Failed to configure native fetcher from HomeView:', error)
|
||
// Don't mark as configured on error, so it can retry on next mount
|
||
}
|
||
}
|
||
|
||
// Initialize system status and native fetcher when component mounts
|
||
onMounted(async () => {
|
||
console.log('🏠 HomeView mounted - checking initial system status and configuring native fetcher...')
|
||
|
||
// Configure native fetcher first (needed for background workers)
|
||
await configureNativeFetcher()
|
||
|
||
// Then check system status
|
||
await checkSystemStatus()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.home-view {
|
||
padding: 20px;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.welcome-section {
|
||
text-align: center;
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 32px;
|
||
font-weight: 700;
|
||
color: white;
|
||
margin: 0 0 8px 0;
|
||
}
|
||
|
||
.welcome-subtitle {
|
||
font-size: 16px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
margin: 0 0 20px 0;
|
||
}
|
||
|
||
.platform-info {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.platform-badge {
|
||
padding: 6px 12px;
|
||
border-radius: 16px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.status-badge {
|
||
padding: 6px 12px;
|
||
border-radius: 16px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.quick-actions {
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: white;
|
||
margin: 0 0 20px 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.action-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
|
||
.system-status {
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.section {
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
/* Mobile responsiveness */
|
||
@media (max-width: 768px) {
|
||
.home-view {
|
||
padding: 16px;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 24px;
|
||
}
|
||
|
||
.action-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.platform-info {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
}
|
||
</style>
|