mesauth-angular
v0.2.14
Published
Angular helper library to connect to a backend API and SignalR hub to surface the current logged-in user and incoming notifications with dark/light theme support
Downloads
1,831
Maintainers
Readme
mesauth-angular
Angular helper library to connect to a backend API and SignalR hub to surface the current logged-in user and incoming notifications with dark/light theme support.
Features
- 🔐 Authentication: User login/logout with API integration
- 🔔 Real-time Notifications: SignalR integration for live notifications
- 🎨 Dark/Light Theme: Automatic theme detection and support
- 🖼️ Avatar Support: Direct API-based avatar loading
- 🍞 Toast Notifications: In-app notification toasts
- 🛡️ HTTP Interceptor: Automatic 403 error handling
Theme Support
The library automatically detects and adapts to your application's theme:
Automatic Theme Detection
The library checks for theme indicators on the <html> element:
class="dark"data-theme="dark"theme="dark"data-coreui-theme="dark"
Dynamic Theme Changes
Theme changes are detected in real-time using MutationObserver, so components automatically update when your app switches themes.
Manual Theme Control
import { ThemeService } from 'mesauth-angular';
// Check current theme
const currentTheme = themeService.currentTheme; // 'light' | 'dark'
// Manually set theme
themeService.setTheme('dark');
// Listen for theme changes
themeService.currentTheme$.subscribe(theme => {
console.log('Theme changed to:', theme);
});Avatar Loading
Avatars are loaded directly from your API using the pattern: GET /auth/{userId}/avatar
- API Endpoint:
GET {apiBaseUrl}/auth/{userId}/avatar - Fallback: UI Avatars service if userId is not available
- Authentication: Uses the same credentials as other API calls
Quick Start
Quick Start
Install (from local folder during development):
cd /path/to/your/angular-app npm install ../path/to/mesauth-angularProvide the service and import components:
- For standalone components/apps: Import
MesAuthModulein your standalone component orapp.config.ts.
Or inimport { MesAuthModule } from 'mesauth-angular'; @Component({ standalone: true, imports: [MesAuthModule, /* other imports */], // ... }) export class MyComponent {}app.config.ts:import { MesAuthModule } from 'mesauth-angular'; export const appConfig: ApplicationConfig = { imports: [MesAuthModule], // ... other config }; - For module-based apps: Import
MesAuthModulein yourAppModuleor feature module.import { MesAuthModule } from 'mesauth-angular'; @NgModule({ imports: [MesAuthModule], // ... other config }) export class AppModule { }
- For standalone components/apps: Import
(Optional) Provide the HTTP interceptor to handle 403 errors:
- The interceptor redirects to
${userBaseUrl}/403?returnUrl=encodedCurrentUrlusingwindow.location.hreffor external URLs (sinceuserBaseUrlmay be outside the client app). - For module-based apps: Add
MesAuthInterceptorto providers inAppModule.import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { MesAuthInterceptor } from 'mesauth-angular'; @NgModule({ // ... other module config ... providers: [ // ... other providers ... { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true } ] }) export class AppModule { } - For standalone apps: Add
MesAuthInterceptorto providers inapp.config.ts.import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { MesAuthInterceptor } from 'mesauth-angular'; export const appConfig: ApplicationConfig = { providers: [ // ... other providers ... { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true } ] };
- The interceptor redirects to
Initialize in your app (e.g.
AppComponentconstructor orAppModulebootstrap):// in AppComponent constructor(private mesAuth: MesAuthService) { this.mesAuth.init({ apiBaseUrl: 'https://api.example.com', withCredentials: true, userBaseUrl: 'https://api.example.com/users' }); this.mesAuth.currentUser$.subscribe(user => console.log('user', user)); this.mesAuth.notifications$.subscribe(n => console.log('notif', n)); }Alternatively, for standalone components or functions (where constructor injection isn't available), use Angular's
inject():// In a standalone component or function const mesAuth = inject(MesAuthService); mesAuth.init({ apiBaseUrl: 'https://api.example.com', withCredentials: true, userBaseUrl: 'https://api.example.com/users' }); mesAuth.currentUser$.subscribe(user => console.log('user', user)); mesAuth.notifications$.subscribe(n => console.log('notif', n));For Standalone Apps (using
bootstrapApplication):After providing the service as above, initialize it using
APP_INITIALIZERin yourapp.config.tsfor app-wide setup, or in the root component.Example in
app.config.ts(add to providers):import { APP_INITIALIZER } from '@angular/core'; import { MesAuthService } from 'mesauth-angular'; export const appConfig: ApplicationConfig = { providers: [ // ... other providers ... MesAuthService, { provide: APP_INITIALIZER, useFactory: (mesAuth: MesAuthService) => () => { mesAuth.init({ apiBaseUrl: 'https://api.example.com', withCredentials: true, userBaseUrl: 'https://api.example.com/users' }); }, deps: [MesAuthService], multi: true } ] };Then, in your root component (e.g.,
AppComponent), subscribe to observables as usual:// In AppComponent (standalone) constructor() { const mesAuth = inject(MesAuthService); mesAuth.currentUser$.subscribe(user => console.log('user', user)); mesAuth.notifications$.subscribe(n => console.log('notif', n)); }
Build the package for publishing:
cd /path/to/mesauth-angular npm install npm run build
Components
Note: All components are standalone and can only be imported in standalone components or apps. If your app uses NgModules, use dynamic imports or convert to standalone.
ma-user-profile
A reusable Angular component for displaying the current user's profile information, with options for navigation and logout.
Description: Renders user details (e.g., name, avatar) fetched via the MesAuthService. Supports custom event handlers for navigation and logout actions.
Inputs: None (data is sourced from the MesAuthService).
Outputs:
onNavigate: Emits an event when the user triggers navigation (e.g., to a profile page). Pass a handler to define behavior.onLogout: Emits an event when the user logs out. Pass a handler to perform logout logic (e.g., clear tokens, redirect).
Usage Example:
<ma-user-profile (onNavigate)="handleNavigation($event)" (onLogout)="handleLogout()"> </ma-user-profile>In your component's TypeScript file:
handleNavigation(event: any) { // Navigate to user profile page this.router.navigate(['/profile']); } handleLogout() { // Perform logout, e.g., clear session and redirect this.mesAuth.logout(); // Assuming a logout method exists this.router.navigate(['/login']); }
ma-notification-panel
A standalone component for displaying a slide-out notification panel with real-time updates.
Description: Shows a list of notifications, allows marking as read/delete, and integrates with toast notifications for new alerts.
Inputs: None.
Outputs: None (uses internal methods for actions).
Usage Example:
<ma-notification-panel #notificationPanel></ma-notification-panel>In your component:
// To open the panel notificationPanel.open();
Changelog
v0.2.13 (Latest)
- 🎨 Notification Format: Cleaned up notification title format by removing redundant
[sourceAppName]prefix - 📱 Improved Layout: Source app name now displayed separately in metadata row for better organization
- 🔔 Consistent Toasts: Toast notifications also updated to use clean title format without app name prefix
v0.2.12
- 📝 HTML Message Support: Added priority support for
messageHtmlovermessagein notifications - 🎨 Rich Text Display: Notifications now render HTML content when available, with fallback to plain text
- 🔔 Enhanced Toasts: Toast notifications also support HTML content with proper rendering
v0.2.9
- 🔐 Credentials Fix: Added
withCredentials: trueto all HTTP requests to properly send authentication cookies - 🐛 403 Forbidden Fix: Resolved authentication issues where API calls were failing due to missing credentials
- 🔧 Consistent Auth: All API endpoints now properly include credentials for authenticated requests
v0.2.8
- 🔄 Route Change Optimization: Improved route change detection with debouncing and selective refreshing
- 🛡️ Protected Route Handling: Only refresh user data on protected routes, avoiding auth flow interference
- 🔧 Smart URL Construction: Fixed double
/authpath issue for auth endpoints when apiBaseUrl includes/auth - ⏱️ Timing Improvements: Added delays and better timing for authentication state management
v0.2.7
- 🔄 Route Change Detection: Added automatic user data refresh when routes change in single-page applications
- 🎯 SPA Support: Handles login scenarios where page doesn't reload but route changes occur
- 🛡️ Optional Dependency: Router integration is optional - service works with or without Router injection
v0.2.6
- 🗑️ Delete Button: Added delete button for read notifications in the read tab
- 🎯 Contextual Actions: Unread notifications show "mark as read" button, read notifications show "delete" button
- 🎨 Visual Feedback: Delete button uses error color on hover for clear destructive action indication
v0.2.5
- 🗂️ Notification Tabs: Added tabs to separate unread and read notifications with unread tab as default
- 📊 Tab Counters: Display notification counts for each tab (Unread/Read)
- 🎯 Improved UX: Better organization of notifications with tab-based navigation
- 🔄 Enhanced Filtering: Load both read and unread notifications for seamless tab switching
v0.2.4
- 🔔 Notification UX: Changed notification delete button to mark-as-read with checkmark icon
- 🔄 Badge Updates: Added automatic badge counter refresh when notifications are marked as read
- 🎯 Event System: Implemented event-driven communication between notification panel and badge components
v0.2.3
- 🧹 Code Cleanup: Removed all console.log and console.error statements for production readiness
- 📚 Documentation: Updated README with comprehensive changelog, theme support guide, and API documentation
- 🏷️ Package Metadata: Updated package description to reflect theme support
v0.2.2
- ✨ Theme Support: Added automatic dark/light theme detection and real-time theme switching
- 🖼️ Avatar API: Changed avatar loading to use API endpoint (
/auth/{userId}/avatar) instead of external service - 🎨 UI Improvements: Better toast styling with proper borders and sizing
v0.2.1
- 🔄 Dynamic Themes: Added real-time theme change detection using MutationObserver
- 🐛 Toast Fixes: Improved toast background and sizing for dark themes
v0.2.0
- 🎨 Initial Theme Support: Basic dark/light theme implementation
- 🖼️ Avatar Updates: Changed to API-based avatar loading
v0.1.20
- 🐛 Bug fixes and improvements
Notes
- The service expects an endpoint
GET {apiBaseUrl}/auth/methat returns the current user. - Avatar endpoint:
GET {apiBaseUrl}/auth/{userId}/avatar - SignalR events used:
ReceiveNotification(adjust to your backend).
Troubleshooting
JIT Compiler Error in Production or AOT Mode
If you encounter an error like "The injectable 'MesAuthService' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available," this typically occurs because:
- The package is being imported directly from source code (e.g., during development) without building it first.
- The client app is running in AOT (Ahead-of-Time) compilation mode, which requires pre-compiled libraries.
- Why JIT is required: Originally,
MesAuthServiceused@Injectable({ providedIn: 'root' }), making it a library-provided service. Angular libraries must be built with tools like ng-packagr to generate AOT-compatible code. If not, or if imported from source, the service requires JIT compilation in the client's app. This change (removingprovidedIn: 'root'and requiring manual provision) allows the service to be compiled in your app's context, supporting both JIT and AOT modes.
Solutions:
Build the package for production/AOT compatibility:
- Ensure you have built the package using
npm run build(which uses ng-packagr or similar to generate AOT-ready code). - Install the built package via npm (e.g., from a local tarball or registry) instead of linking to the source folder.
- Ensure you have built the package using
For development (if you must link to source):
- Switch your Angular app to JIT mode by bootstrapping with
@angular/platform-browser-dynamicinstead of@angular/platform-browser. - Example in
main.ts:import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; platformBrowserDynamic().bootstrapModule(AppModule); - Note: JIT is not recommended for production; use AOT for better performance.
- Switch your Angular app to JIT mode by bootstrapping with
Verify imports:
- Ensure you're importing from the built package (e.g.,
import { MesAuthService } from 'mesauth-angular';) and not from thesrcfolder. - If using standalone components, confirm the service is available in the injection context.
- Ensure you're importing from the built package (e.g.,
If issues persist, check your Angular version compatibility and ensure the package's package.json includes the correct entry points for AOT.
Components Appear Empty
If components like ma-user or ma-user-profile render as empty:
- Ensure
MesAuthServiceis provided in your app (see Quick Start step 2). - Check browser console for logs from components (e.g., "UserProfileComponent: currentUser").
- If
currentUseris null, the component shows a login button—verify the service is initialized and the API returns user data. - For standalone apps, confirm
APP_INITIALIZERor manual init is used.
Dynamic import in a module-based component
import { Component } from '@angular/core';
@Component({...}) export class DefaultHeaderComponent { async ngOnInit() { const { MaUserComponent } = await import('mesauth-angular'); // Use it dynamically } }
