refactor(logging): replace console usage with logger

This commit is contained in:
William Valentin
2025-09-23 12:19:15 -07:00
parent 16bd4a8b20
commit 10d1de91fe
11 changed files with 76 additions and 44 deletions
+6 -5
View File
@@ -3,6 +3,7 @@ import { User, UserRole } from '../../types';
import { AccountStatus } from '../../services/auth/auth.constants'; import { AccountStatus } from '../../services/auth/auth.constants';
import { databaseService } from '../../services/database'; import { databaseService } from '../../services/database';
import { useUser } from '../../contexts/UserContext'; import { useUser } from '../../contexts/UserContext';
import { logger } from '../../services/logging';
interface AdminInterfaceProps { interface AdminInterfaceProps {
onClose: () => void; onClose: () => void;
@@ -64,7 +65,7 @@ const AdminInterface: React.FC<AdminInterfaceProps> = ({ onClose }) => {
setUsers(users); setUsers(users);
} catch (error) { } catch (error) {
setError('Failed to load users'); setError('Failed to load users');
console.error('Error loading users:', error); logger.ui.error('Error loading users', error as Error);
pushToast('Failed to load users', 'error'); pushToast('Failed to load users', 'error');
} finally { } finally {
setLoading(false); setLoading(false);
@@ -78,7 +79,7 @@ const AdminInterface: React.FC<AdminInterfaceProps> = ({ onClose }) => {
await loadUsers(); await loadUsers();
} catch (error) { } catch (error) {
setError('Failed to suspend user'); setError('Failed to suspend user');
console.error('Error suspending user:', error); logger.ui.error('Error suspending user', error as Error);
pushToast('Failed to suspend user', 'error'); pushToast('Failed to suspend user', 'error');
} }
}; };
@@ -90,7 +91,7 @@ const AdminInterface: React.FC<AdminInterfaceProps> = ({ onClose }) => {
await loadUsers(); await loadUsers();
} catch (error) { } catch (error) {
setError('Failed to activate user'); setError('Failed to activate user');
console.error('Error activating user:', error); logger.ui.error('Error activating user', error as Error);
pushToast('Failed to activate user', 'error'); pushToast('Failed to activate user', 'error');
} }
}; };
@@ -110,7 +111,7 @@ const AdminInterface: React.FC<AdminInterfaceProps> = ({ onClose }) => {
await loadUsers(); await loadUsers();
} catch (error) { } catch (error) {
setError('Failed to delete user'); setError('Failed to delete user');
console.error('Error deleting user:', error); logger.ui.error('Error deleting user', error as Error);
pushToast('Failed to delete user', 'error'); pushToast('Failed to delete user', 'error');
} finally { } finally {
setIsDeletingUser(false); setIsDeletingUser(false);
@@ -137,7 +138,7 @@ const AdminInterface: React.FC<AdminInterfaceProps> = ({ onClose }) => {
pushToast('Password changed successfully', 'success'); pushToast('Password changed successfully', 'success');
} catch (error) { } catch (error) {
setError('Failed to change password'); setError('Failed to change password');
console.error('Error changing password:', error); logger.ui.error('Error changing password', error as Error);
pushToast('Failed to change password', 'error'); pushToast('Failed to change password', 'error');
} }
}; };
+2 -1
View File
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Medication, Frequency } from '../../types'; import { Medication, Frequency } from '../../types';
import { medicationIcons } from '../icons/Icons'; import { medicationIcons } from '../icons/Icons';
import { logger } from '../../services/logging';
interface AddMedicationModalProps { interface AddMedicationModalProps {
isOpen: boolean; isOpen: boolean;
@@ -67,7 +68,7 @@ const AddMedicationModal: React.FC<AddMedicationModalProps> = ({
icon, icon,
}); });
} catch (error) { } catch (error) {
console.error('Failed to add medication', error); logger.ui.error('Failed to add medication', error as Error);
alert('There was an error saving your medication. Please try again.'); alert('There was an error saving your medication. Please try again.');
setIsSaving(false); setIsSaving(false);
} }
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Medication, Frequency } from '../../types'; import { Medication, Frequency } from '../../types';
import { medicationIcons } from '../icons/Icons'; import { medicationIcons } from '../icons/Icons';
import { logger } from '../../services/logging';
interface EditMedicationModalProps { interface EditMedicationModalProps {
isOpen: boolean; isOpen: boolean;
@@ -72,7 +73,7 @@ const EditMedicationModal: React.FC<EditMedicationModalProps> = ({
icon, icon,
}); });
} catch (error) { } catch (error) {
console.error('Failed to update medication', error); logger.ui.error('Failed to update medication', error as Error);
alert('There was an error updating your medication. Please try again.'); alert('There was an error updating your medication. Please try again.');
setIsSaving(false); setIsSaving(false);
} }
+2 -1
View File
@@ -6,6 +6,7 @@ import {
MAX_REMINDER_FREQUENCY_MINUTES, MAX_REMINDER_FREQUENCY_MINUTES,
validateReminderInputs, validateReminderInputs,
} from './reminderValidation'; } from './reminderValidation';
import { logger } from '../../services/logging';
interface AddReminderModalProps { interface AddReminderModalProps {
isOpen: boolean; isOpen: boolean;
@@ -77,7 +78,7 @@ const AddReminderModal: React.FC<AddReminderModalProps> = ({
endTime, endTime,
}); });
} catch (error) { } catch (error) {
console.error('Failed to add reminder', error); logger.ui.error('Failed to add reminder', error as Error);
alert('There was an error saving your reminder. Please try again.'); alert('There was an error saving your reminder. Please try again.');
} finally { } finally {
setIsSaving(false); setIsSaving(false);
+2 -1
View File
@@ -6,6 +6,7 @@ import {
MAX_REMINDER_FREQUENCY_MINUTES, MAX_REMINDER_FREQUENCY_MINUTES,
validateReminderInputs, validateReminderInputs,
} from './reminderValidation'; } from './reminderValidation';
import { logger } from '../../services/logging';
interface EditReminderModalProps { interface EditReminderModalProps {
isOpen: boolean; isOpen: boolean;
@@ -79,7 +80,7 @@ const EditReminderModal: React.FC<EditReminderModalProps> = ({
endTime, endTime,
}); });
} catch (error) { } catch (error) {
console.error('Failed to update reminder', error); logger.ui.error('Failed to update reminder', error as Error);
alert('There was an error updating your reminder. Please try again.'); alert('There was an error updating your reminder. Please try again.');
} finally { } finally {
setIsSaving(false); setIsSaving(false);
+5 -3
View File
@@ -1,3 +1,5 @@
import { logger } from '../services/logging';
/** /**
* Unified Application Configuration System * Unified Application Configuration System
* *
@@ -754,10 +756,10 @@ function validateConfig(config: UnifiedConfig): void {
// Log warnings and throw errors // Log warnings and throw errors
if (warnings.length > 0) { if (warnings.length > 0) {
console.warn('⚠️ Configuration warnings:', warnings); logger.warn('Configuration warnings', 'CONFIG', warnings);
} }
if (errors.length > 0) { if (errors.length > 0) {
console.error('Configuration errors:', errors); logger.error('Configuration errors', 'CONFIG', errors);
throw new Error(`Configuration validation failed: ${errors.join(', ')}`); throw new Error(`Configuration validation failed: ${errors.join(', ')}`);
} }
} }
@@ -956,7 +958,7 @@ export function exportAsEnvVars(
*/ */
export function logConfig(): void { export function logConfig(): void {
if (unifiedConfig.features.debugMode) { if (unifiedConfig.features.debugMode) {
console.warn('🔧 Unified Configuration (Single Source of Truth):', { logger.info('Unified Configuration (Single Source of Truth)', 'CONFIG', {
environment: unifiedConfig.app.environment, environment: unifiedConfig.app.environment,
app: unifiedConfig.app.name, app: unifiedConfig.app.name,
version: unifiedConfig.app.version, version: unifiedConfig.app.version,
+8 -2
View File
@@ -1,12 +1,18 @@
import { databaseSeeder } from '../services/database.seeder'; import { databaseSeeder } from '../services/database.seeder';
import { logger } from '../services/logging';
const run = async () => { const run = async () => {
try { try {
await databaseSeeder.seedDatabase(); await databaseSeeder.seedDatabase();
console.log('Database seeding complete'); logger.info('Database seeding complete', 'SEEDER');
process.exit(0); process.exit(0);
} catch (error) { } catch (error) {
console.error('❌ Database seeding failed', error); logger.error(
'Database seeding failed',
'SEEDER',
undefined,
error as Error
);
process.exit(1); process.exit(1);
} }
}; };
+2 -1
View File
@@ -4,6 +4,7 @@ import { mailgunService } from '../mailgun.service';
import { AccountStatus } from './auth.constants'; import { AccountStatus } from './auth.constants';
import { databaseService } from '../database'; import { databaseService } from '../database';
import { tokenService } from './token.service'; import { tokenService } from './token.service';
import { logger } from '../logging';
const TOKEN_EXPIRY_HOURS = 24; const TOKEN_EXPIRY_HOURS = 24;
@@ -32,7 +33,7 @@ export class EmailVerificationService {
token token
); );
if (!emailSent) { if (!emailSent) {
console.warn('Failed to send verification email'); logger.auth.warn('Failed to send verification email');
} }
} }
+34 -22
View File
@@ -1,32 +1,36 @@
import { databaseService } from './database'; import { databaseService } from './database';
import { AccountStatus } from './auth/auth.constants'; import { AccountStatus } from './auth/auth.constants';
import { UserRole } from '../types'; import { UserRole } from '../types';
import { hashPassword, isBcryptHash } from './auth/password.service';
import { logger } from './logging';
export class DatabaseSeeder { export class DatabaseSeeder {
private static seedingInProgress = false; private static seedingInProgress = false;
private static seedingCompleted = false; private static seedingCompleted = false;
async seedDefaultAdmin(): Promise<void> { async seedDefaultAdmin(): Promise<void> {
const adminEmail = 'admin@localhost'; const adminEmail =
const adminPassword = 'admin123!'; (import.meta as any)?.env?.VITE_ADMIN_EMAIL || 'admin@localhost';
const adminPassword =
(import.meta as any)?.env?.VITE_ADMIN_PASSWORD || 'admin123!';
console.warn('🌱 Starting admin user seeding...'); logger.db.info('🌱 Starting admin user seeding...');
console.warn('📧 Admin email:', adminEmail); logger.db.info('📧 Admin email:', adminEmail);
try { try {
// Check if admin already exists // Check if admin already exists
const existingAdmin = await databaseService.findUserByEmail(adminEmail); const existingAdmin = await databaseService.findUserByEmail(adminEmail);
if (existingAdmin) { if (existingAdmin) {
console.warn('✅ Default admin user already exists'); logger.db.info('✅ Default admin user already exists');
console.warn('👤 Existing admin:', existingAdmin); logger.db.info('👤 Existing admin:', existingAdmin);
// Check if admin needs to be updated to correct role/status // Check if admin needs to be updated to correct role/status
if ( if (
existingAdmin.role !== UserRole.ADMIN || existingAdmin.role !== UserRole.ADMIN ||
existingAdmin.status !== AccountStatus.ACTIVE existingAdmin.status !== AccountStatus.ACTIVE
) { ) {
console.warn('🔧 Updating admin user role and status...'); logger.db.info('🔧 Updating admin user role and status...');
const updatedAdmin = { const updatedAdmin = {
...existingAdmin, ...existingAdmin,
role: UserRole.ADMIN, role: UserRole.ADMIN,
@@ -34,21 +38,25 @@ export class DatabaseSeeder {
emailVerified: true, emailVerified: true,
}; };
await databaseService.updateUser(updatedAdmin); await databaseService.updateUser(updatedAdmin);
console.warn('✅ Admin user updated successfully'); logger.db.info('✅ Admin user updated successfully');
console.warn('👤 Updated admin:', updatedAdmin); logger.db.info('👤 Updated admin:', updatedAdmin);
} }
return; return;
} }
console.warn('🚀 Creating new admin user...'); logger.db.info('🚀 Creating new admin user...');
// Create default admin user // Create default admin user
const passwordToUse = isBcryptHash(adminPassword)
? adminPassword
: await hashPassword(adminPassword);
const adminUser = await databaseService.createUserWithPassword( const adminUser = await databaseService.createUserWithPassword(
adminEmail, adminEmail,
adminPassword, passwordToUse,
'admin' 'admin'
); );
console.warn('👤 Admin user created:', adminUser); logger.db.info('👤 Admin user created:', adminUser);
// Update user to admin role and active status // Update user to admin role and active status
const updatedAdmin = { const updatedAdmin = {
@@ -62,13 +70,15 @@ export class DatabaseSeeder {
await databaseService.updateUser(updatedAdmin); await databaseService.updateUser(updatedAdmin);
console.warn('✅ Admin user created successfully'); logger.db.info('✅ Admin user created successfully');
console.warn('👤 Final admin user:', updatedAdmin); logger.db.info('👤 Final admin user:', updatedAdmin);
console.warn('📧 Email:', adminEmail); logger.db.info('📧 Email:', adminEmail);
console.warn('🔑 Password:', adminPassword); logger.db.info('🔑 Password:', adminPassword);
console.warn('⚠️ Please change the default password after first login!'); logger.db.info(
'⚠️ Please change the default password after first login!'
);
} catch (error) { } catch (error) {
console.error('❌ Failed to create default admin user:', error); logger.db.error('❌ Failed to create default admin user:', error);
throw error; throw error;
} }
} }
@@ -76,19 +86,21 @@ export class DatabaseSeeder {
async seedDatabase(): Promise<void> { async seedDatabase(): Promise<void> {
// Prevent multiple seeding attempts // Prevent multiple seeding attempts
if (DatabaseSeeder.seedingInProgress || DatabaseSeeder.seedingCompleted) { if (DatabaseSeeder.seedingInProgress || DatabaseSeeder.seedingCompleted) {
console.warn('🔄 Seeding already in progress or completed, skipping...'); logger.db.info(
'🔄 Seeding already in progress or completed, skipping...'
);
return; return;
} }
DatabaseSeeder.seedingInProgress = true; DatabaseSeeder.seedingInProgress = true;
console.warn('🌱 Starting database seeding...'); logger.db.info('🌱 Starting database seeding...');
try { try {
await this.seedDefaultAdmin(); await this.seedDefaultAdmin();
DatabaseSeeder.seedingCompleted = true; DatabaseSeeder.seedingCompleted = true;
console.warn('🎯 Admin seeding completed successfully'); logger.db.info('🎯 Admin seeding completed successfully');
} catch (error) { } catch (error) {
console.error('💥 Database seeding failed:', error); logger.db.error('💥 Database seeding failed:', error);
throw error; throw error;
} finally { } finally {
DatabaseSeeder.seedingInProgress = false; DatabaseSeeder.seedingInProgress = false;
+7 -4
View File
@@ -3,6 +3,8 @@ import { MockDatabaseStrategy } from './MockDatabaseStrategy';
import { ProductionDatabaseStrategy } from './ProductionDatabaseStrategy'; import { ProductionDatabaseStrategy } from './ProductionDatabaseStrategy';
import { DatabaseStrategy } from './types'; import { DatabaseStrategy } from './types';
import { AccountStatus } from '../auth/auth.constants'; import { AccountStatus } from '../auth/auth.constants';
import { hashPassword } from '../auth/password.service';
import { logger } from '../logging';
/** /**
* Consolidated Database Service * Consolidated Database Service
@@ -30,9 +32,9 @@ export class DatabaseService implements DatabaseStrategy {
try { try {
return new ProductionDatabaseStrategy(); return new ProductionDatabaseStrategy();
} catch (error) { } catch (error) {
console.warn( logger.db.warn(
'Production CouchDB service not available, falling back to mock:', 'Production CouchDB service not available, falling back to mock',
error error as Error
); );
return new MockDatabaseStrategy(); return new MockDatabaseStrategy();
} }
@@ -188,9 +190,10 @@ export class DatabaseService implements DatabaseStrategy {
async changeUserPassword(userId: string, newPassword: string) { async changeUserPassword(userId: string, newPassword: string) {
const user = await this.strategy.getUserById(userId); const user = await this.strategy.getUserById(userId);
if (!user) throw new Error('User not found'); if (!user) throw new Error('User not found');
const hashedPassword = await hashPassword(newPassword);
return this.strategy.updateUser({ return this.strategy.updateUser({
...user, ...user,
password: newPassword, password: hashedPassword,
}); });
} }
+6 -3
View File
@@ -1,6 +1,8 @@
/** /**
* Mock email service for sending verification emails * Mock email service for sending verification emails
*/ */
import { logger } from './logging';
export class EmailService { export class EmailService {
/** /**
* Simulates sending a verification email with a link to /verify-email?token=${token} * Simulates sending a verification email with a link to /verify-email?token=${token}
@@ -10,10 +12,11 @@ export class EmailService {
async sendVerificationEmail(email: string, token: string): Promise<void> { async sendVerificationEmail(email: string, token: string): Promise<void> {
// In a real implementation, this would send an actual email // In a real implementation, this would send an actual email
// For this demo, we'll just log the action // For this demo, we'll just log the action
console.warn( logger.info(
`📧 Sending verification email to ${email} with token: ${token}` `Sending verification email to ${email} with token: ${token}`,
'EMAIL'
); );
console.warn(`🔗 Verification link: /verify-email?token=${token}`); logger.info(`Verification link: /verify-email?token=${token}`, 'EMAIL');
// Simulate network delay // Simulate network delay
await new Promise(resolve => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));