# Quick Reference Guide - New Improvements ## 🚀 How to Use New Features ### 1. Validation Service #### Import and inject: ```typescript import { ValidationService } from '../../services/validation.service'; constructor(private validationService: ValidationService) {} ``` #### Validate a single field: ```typescript onFieldChange(field: string, value: any) { const errors = this.validationService.validateItem({ [field]: value }); if (errors[field]) { this.snackBar.open(`Error: ${errors[field]}`, 'Close', { duration: 3000 }); return; } // Proceed with save } ``` #### Validate entire object: ```typescript onSubmit() { const errors = this.validationService.validateItem(this.item); if (Object.keys(errors).length > 0) { const errorMsg = Object.values(errors).join(', '); this.snackBar.open(`Validation failed: ${errorMsg}`, 'Close', { duration: 4000 }); return; } // Proceed with API call this.apiService.createItem(...); } ``` #### Available validators: - `validateRequired(value)` - Checks for empty values - `validateNumber(value, min?, max?)` - Validates numeric input - `validatePrice(value)` - Ensures price >= 0 - `validateQuantity(value)` - Validates integer >= 0 - `validateUrl(value)` - Checks URL format - `validateImageUrl(value)` - Validates image extensions - `validateId(value)` - Ensures URL-safe ID (2-50 chars) - `validatePriority(value)` - Validates 0-9999 - `validateCurrency(value)` - USD, EUR, RUB, GBP, UAH - `validateArrayNotEmpty(arr)` - Ensures non-empty array --- ### 2. Toast Notification Service #### Import and inject: ```typescript import { ToastService } from '../../services/toast.service'; constructor(private toast: ToastService) {} ``` #### Show notifications: ```typescript // Success (green, 2s) this.toast.success('Item saved successfully!'); // Error (red, 4s) this.toast.error('Failed to save item'); // Warning (orange, 3s) this.toast.warning('This action will delete all items'); // Info (blue, 2s) this.toast.info('Loading data...'); // Custom duration this.toast.success('Saved!', 5000); // 5 seconds ``` #### Best practices: - Use `success()` for completed operations - Use `error()` for failures with specific message - Use `warning()` before dangerous actions - Use `info()` for status updates --- ### 3. Loading Skeleton Component #### Import in component: ```typescript import { LoadingSkeletonComponent } from '../../components/loading-skeleton/loading-skeleton.component'; @Component({ imports: [ // ... other imports LoadingSkeletonComponent ] }) ``` #### Use in template: ```html @if (loading()) { } @else { } @if (loading()) { } @else { } @if (loading()) { } @else { } @if (loading()) { } @else { } ``` #### Available types: - `tree` - Nested hierarchy with indentation (sidebar) - `card` - Grid of rectangular cards - `list` - Vertical list of items - `form` - Form fields with labels --- ### 4. Enhanced Error Handling The API service now provides detailed error messages automatically: #### Error codes and messages: - **400** - "Invalid request data" - **401** - "Unauthorized - please log in" - **403** - "You don't have permission to perform this action" - **404** - "Resource not found" - **409** - "Conflict - resource already exists" - **422** - "Validation failed" - **500** - "Internal server error" - **503** - "Service temporarily unavailable" #### Example usage: ```typescript this.apiService.createItem(item).subscribe({ next: (created) => { this.toast.success('Item created!'); }, error: (err) => { // err.message already contains user-friendly message this.toast.error(err.message || 'Failed to create item'); } }); ``` --- ### 5. Enhanced Confirmation Dialogs #### Example with count information: ```typescript deleteCategory(node: CategoryNode) { const subCount = node.children?.length || 0; const message = subCount > 0 ? `Are you sure you want to delete "${node.name}"? This will also delete ${subCount} subcategory(ies) and all their items. This action cannot be undone.` : `Are you sure you want to delete "${node.name}"? This action cannot be undone.`; const dialogRef = this.dialog.open(ConfirmDialogComponent, { data: { title: 'Delete Category', message: message, confirmText: 'Delete', cancelText: 'Cancel', dangerous: true // Shows red confirm button } }); dialogRef.afterClosed().subscribe(result => { if (result) { // User confirmed, proceed with deletion } }); } ``` #### Dialog options: - `title` - Dialog header - `message` - Description text (can include HTML) - `confirmText` - Confirm button label (default: "Confirm") - `cancelText` - Cancel button label (default: "Cancel") - `dangerous` - Makes confirm button red (for destructive actions) --- ## 🎨 Styling Tips ### Toast colors are automatic: ```typescript // Green background this.toast.success('...'); // Red background this.toast.error('...'); // Orange background this.toast.warning('...'); // Blue background this.toast.info('...'); ``` ### Loading skeletons animate automatically: - Shimmer effect from left to right - Gray placeholders that match content structure - No additional CSS needed --- ## 📋 Component Integration Checklist When adding these features to a new component: ### For validation: - [ ] Import `ValidationService` - [ ] Inject in constructor - [ ] Call validation before API calls - [ ] Display errors via toast or inline ### For loading states: - [ ] Import `LoadingSkeletonComponent` - [ ] Add to `imports` array - [ ] Add `loading` signal - [ ] Wrap content with `@if (loading()) { skeleton } @else { content }` ### For toasts: - [ ] Import `ToastService` - [ ] Inject in constructor - [ ] Replace MatSnackBar calls with toast methods - [ ] Use appropriate type (success/error/warning/info) ### For error handling: - [ ] Handle `error` callback in subscribe - [ ] Use `err.message` for user-friendly message - [ ] Display via toast service - [ ] Consider retry logic for critical operations --- ## 🐛 Common Patterns ### Pattern 1: Form submission with validation ```typescript onSubmit() { // Validate const errors = this.validationService.validateItem(this.item()); if (Object.keys(errors).length > 0) { const errorMsg = Object.values(errors).join(', '); this.toast.error(`Validation failed: ${errorMsg}`); return; } // Save this.saving.set(true); this.apiService.updateItem(this.itemId(), this.item()).subscribe({ next: (updated) => { this.item.set(updated); this.toast.success('Item saved successfully!'); this.saving.set(false); }, error: (err) => { this.toast.error(err.message || 'Failed to save item'); this.saving.set(false); } }); } ``` ### Pattern 2: Loading data with skeleton ```typescript // Component loading = signal(true); ngOnInit() { this.loadData(); } loadData() { this.loading.set(true); this.apiService.getData().subscribe({ next: (data) => { this.data.set(data); this.loading.set(false); }, error: (err) => { this.toast.error(err.message || 'Failed to load data'); this.loading.set(false); } }); } // Template @if (loading()) { } @else { @for (item of data(); track item.id) {
{{ item.name }}
} } ``` ### Pattern 3: Destructive action with confirmation ```typescript deleteItem() { const dialogRef = this.dialog.open(ConfirmDialogComponent, { data: { title: 'Delete Item', message: `Are you sure you want to delete "${this.item().name}"? This action cannot be undone.`, confirmText: 'Delete', cancelText: 'Cancel', dangerous: true } }); dialogRef.afterClosed().subscribe(result => { if (result) { this.apiService.deleteItem(this.itemId()).subscribe({ next: () => { this.toast.success('Item deleted successfully'); this.router.navigate(['/items']); }, error: (err) => { this.toast.error(err.message || 'Failed to delete item'); } }); } }); } ``` --- ## ✅ Testing Your Implementation ### Test validation: 1. Try submitting empty form → Should show "Name is required" 2. Try negative price → Should show "Price must be at least 0" 3. Try invalid quantity → Should show "Quantity must be a non-negative integer" ### Test toasts: 1. Success action → Should show green toast 2. Failed action → Should show red toast 3. Multiple toasts → Should queue properly ### Test loading skeletons: 1. Slow network → Should show skeleton first 2. Fast network → Should briefly show skeleton 3. Skeleton should match content structure ### Test error handling: 1. Network error → Should show user-friendly message 2. 404 error → Should show "Resource not found" 3. 500 error → Should show "Internal server error" --- ## 🎯 Migration Guide ### Replace old MatSnackBar: ```typescript // OLD this.snackBar.open('Saved!', 'Close', { duration: 2000 }); this.snackBar.open('Error!', 'Close', { duration: 3000 }); // NEW this.toast.success('Saved!'); this.toast.error('Error!'); ``` ### Replace old spinners: ```html @if (loading()) { } @if (loading()) { } ``` ### Add validation to existing forms: ```typescript // Before API call, add: const errors = this.validationService.validateItem(this.item); if (Object.keys(errors).length > 0) { this.toast.error(`Validation errors: ${Object.values(errors).join(', ')}`); return; } ``` --- ## 📚 Additional Resources - **IMPROVEMENTS.md** - Full improvement roadmap - **URGENT-IMPROVEMENTS-COMPLETED.md** - Implementation details - **API.md** - API documentation For questions or issues, check the implementation in: - `src/app/pages/project-view/` - Reference implementation - `src/app/pages/item-editor/` - Validation examples - `src/app/services/` - Service documentation