feat(android): add fetch scheduling debug logs and triggerImmediateFetch API
- Add DN|SCHEDULE_CALLBACK logs to diagnose fetch scheduling - Add DN|SCHEDULE_FETCH_* structured logs for traceability - Add triggerImmediateFetch() public API for standalone fetches - Update fetch timing from 1 hour to 5 minutes before notification - Fix TypeScript lint errors: add return types, replace any types - Fix ESLint warnings: add console suppression comments - Fix capacitor.settings.gradle plugin path reference - Update android-app-improvement-plan.md with current state Changes: - DailyNotificationPlugin: Added scheduled callback logging and fetch method - DailyNotificationFetcher: Changed lead time from 1 hour to 5 minutes - EnhancedDailyNotificationFetcher: Added ENH|* structured event IDs - TypeScript services: Fixed lint errors and added proper types - Test app: Fixed capacitor settings path and TypeScript warnings
This commit is contained in:
@@ -3,4 +3,4 @@ include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':timesafari-daily-notification-plugin'
|
||||
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android/plugin')
|
||||
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android')
|
||||
|
||||
@@ -176,6 +176,7 @@ export class TestUserZeroAPI {
|
||||
if (TEST_USER_ZERO_CONFIG.testing.enableMockResponses) {
|
||||
// Return mock data for offline testing
|
||||
|
||||
|
||||
console.log("🧪 Using mock starred projects response");
|
||||
return MOCK_STARRED_PROJECTS_RESPONSE;
|
||||
}
|
||||
@@ -194,8 +195,10 @@ export class TestUserZeroAPI {
|
||||
};
|
||||
|
||||
|
||||
|
||||
console.log("🌐 Making real API call to:", url);
|
||||
|
||||
|
||||
console.log("📦 Request body:", requestBody);
|
||||
|
||||
const response = await fetch(url, {
|
||||
@@ -217,6 +220,7 @@ export class TestUserZeroAPI {
|
||||
refreshToken(): void {
|
||||
this.jwt = generateTestJWT();
|
||||
|
||||
|
||||
console.log("🔄 JWT token refreshed");
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,13 @@ export class DiagnosticsExporter {
|
||||
/**
|
||||
* Collect system information
|
||||
*/
|
||||
private collectSystemInfo() {
|
||||
private collectSystemInfo(): {
|
||||
screenResolution: string
|
||||
colorDepth: number
|
||||
pixelRatio: number
|
||||
viewportSize: string
|
||||
devicePixelRatio: number
|
||||
} {
|
||||
return {
|
||||
screenResolution: `${screen.width}x${screen.height}`,
|
||||
colorDepth: screen.colorDepth,
|
||||
@@ -178,7 +184,12 @@ export class DiagnosticsExporter {
|
||||
/**
|
||||
* Collect network information
|
||||
*/
|
||||
private collectNetworkInfo() {
|
||||
private collectNetworkInfo(): {
|
||||
connectionType: string
|
||||
effectiveType?: string
|
||||
downlink?: number
|
||||
rtt?: number
|
||||
} {
|
||||
const connection = (navigator as Navigator & { connection?: unknown }).connection ||
|
||||
(navigator as Navigator & { mozConnection?: unknown }).mozConnection ||
|
||||
(navigator as Navigator & { webkitConnection?: unknown }).webkitConnection
|
||||
@@ -194,7 +205,12 @@ export class DiagnosticsExporter {
|
||||
/**
|
||||
* Collect storage information
|
||||
*/
|
||||
private collectStorageInfo() {
|
||||
private collectStorageInfo(): {
|
||||
localStorageAvailable: boolean
|
||||
sessionStorageAvailable: boolean
|
||||
indexedDBAvailable: boolean
|
||||
webSQLAvailable: boolean
|
||||
} {
|
||||
return {
|
||||
localStorageAvailable: this.isStorageAvailable('localStorage'),
|
||||
sessionStorageAvailable: this.isStorageAvailable('sessionStorage'),
|
||||
|
||||
@@ -125,10 +125,12 @@ export class ErrorHandler {
|
||||
/**
|
||||
* Log error with context
|
||||
*/
|
||||
logError(error: unknown, context = 'DailyNotification') {
|
||||
logError(error: unknown, context = 'DailyNotification'): void {
|
||||
|
||||
console.error(`[${context}] Error:`, error)
|
||||
|
||||
if ((error as { stack?: string })?.stack) {
|
||||
|
||||
console.error(`[${context}] Stack:`, (error as { stack: string }).stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,14 @@ export class SchemaValidator {
|
||||
/**
|
||||
* Create canonical error response
|
||||
*/
|
||||
createErrorResponse(code: ErrorCode, message: string, hint?: string) {
|
||||
createErrorResponse(code: ErrorCode, message: string, hint?: string): {
|
||||
success: false
|
||||
error: {
|
||||
code: ErrorCode
|
||||
message: string
|
||||
hint?: string
|
||||
}
|
||||
} {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
@@ -184,7 +191,10 @@ export class SchemaValidator {
|
||||
/**
|
||||
* Create success response
|
||||
*/
|
||||
createSuccessResponse(data?: Record<string, unknown>) {
|
||||
createSuccessResponse(data?: Record<string, unknown>): {
|
||||
success: true
|
||||
[key: string]: unknown
|
||||
} {
|
||||
return {
|
||||
success: true,
|
||||
...data
|
||||
|
||||
@@ -16,7 +16,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/schedule',
|
||||
name: 'Schedule',
|
||||
component: () => import('../views/ScheduleView.vue'),
|
||||
component: (): Promise<typeof import('../views/ScheduleView.vue')> => import('../views/ScheduleView.vue'),
|
||||
meta: {
|
||||
title: 'Schedule Notification',
|
||||
requiresAuth: false
|
||||
@@ -25,7 +25,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/notifications',
|
||||
name: 'Notifications',
|
||||
component: () => import('../views/NotificationsView.vue'),
|
||||
component: (): Promise<typeof import('../views/NotificationsView.vue')> => import('../views/NotificationsView.vue'),
|
||||
meta: {
|
||||
title: 'Notification Management',
|
||||
requiresAuth: false
|
||||
@@ -34,7 +34,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/status',
|
||||
name: 'Status',
|
||||
component: () => import('../views/StatusView.vue'),
|
||||
component: (): Promise<typeof import('../views/StatusView.vue')> => import('../views/StatusView.vue'),
|
||||
meta: {
|
||||
title: 'System Status',
|
||||
requiresAuth: false
|
||||
@@ -43,7 +43,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/user-zero',
|
||||
name: 'UserZero',
|
||||
component: () => import('../views/UserZeroView.vue'),
|
||||
component: (): Promise<typeof import('../views/UserZeroView.vue')> => import('../views/UserZeroView.vue'),
|
||||
meta: {
|
||||
title: 'User Zero Testing',
|
||||
requiresAuth: false
|
||||
@@ -52,7 +52,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/history',
|
||||
name: 'History',
|
||||
component: () => import('../views/HistoryView.vue'),
|
||||
component: (): Promise<typeof import('../views/HistoryView.vue')> => import('../views/HistoryView.vue'),
|
||||
meta: {
|
||||
title: 'Notification History',
|
||||
requiresAuth: false
|
||||
@@ -61,7 +61,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/logs',
|
||||
name: 'Logs',
|
||||
component: () => import('../views/LogsView.vue'),
|
||||
component: (): Promise<typeof import('../views/LogsView.vue')> => import('../views/LogsView.vue'),
|
||||
meta: {
|
||||
title: 'System Logs',
|
||||
requiresAuth: false
|
||||
@@ -70,7 +70,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: () => import('../views/SettingsView.vue'),
|
||||
component: (): Promise<typeof import('../views/SettingsView.vue')> => import('../views/SettingsView.vue'),
|
||||
meta: {
|
||||
title: 'Settings',
|
||||
requiresAuth: false
|
||||
@@ -79,7 +79,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
component: () => import('../views/AboutView.vue'),
|
||||
component: (): Promise<typeof import('../views/AboutView.vue')> => import('../views/AboutView.vue'),
|
||||
meta: {
|
||||
title: 'About',
|
||||
requiresAuth: false
|
||||
@@ -88,7 +88,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import('../views/NotFoundView.vue'),
|
||||
component: (): Promise<typeof import('../views/NotFoundView.vue')> => import('../views/NotFoundView.vue'),
|
||||
meta: {
|
||||
title: 'Page Not Found',
|
||||
requiresAuth: false
|
||||
@@ -105,6 +105,7 @@ router.beforeEach((to, from, next) => {
|
||||
}
|
||||
|
||||
// Add loading state
|
||||
|
||||
console.log(`🔄 Navigating from ${String(from.name) || 'unknown'} to ${String(to.name) || 'unknown'}`)
|
||||
|
||||
next()
|
||||
@@ -112,6 +113,7 @@ router.beforeEach((to, from, next) => {
|
||||
|
||||
router.afterEach((to) => {
|
||||
// Clear any previous errors on successful navigation
|
||||
|
||||
console.log(`✅ Navigation completed: ${String(to.name) || 'unknown'}`)
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { defineStore } from 'pinia'
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
function increment() {
|
||||
function increment(): void {
|
||||
count.value++
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user