improvements are done

This commit is contained in:
sdarbinyan
2026-01-22 00:41:13 +04:00
parent a1a2a69fd0
commit 0f3d0ae3ef
27 changed files with 2115 additions and 107 deletions

430
QUICK-REFERENCE.md Normal file
View File

@@ -0,0 +1,430 @@
# 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
<!-- For tree/sidebar -->
@if (loading()) {
<app-loading-skeleton type="tree"></app-loading-skeleton>
} @else {
<!-- Your tree content -->
}
<!-- For card layouts -->
@if (loading()) {
<app-loading-skeleton type="card"></app-loading-skeleton>
} @else {
<!-- Your card content -->
}
<!-- For list views -->
@if (loading()) {
<app-loading-skeleton type="list"></app-loading-skeleton>
} @else {
<!-- Your list content -->
}
<!-- For forms -->
@if (loading()) {
<app-loading-skeleton type="form"></app-loading-skeleton>
} @else {
<!-- Your form content -->
}
```
#### 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()) {
<app-loading-skeleton type="list"></app-loading-skeleton>
} @else {
@for (item of data(); track item.id) {
<div>{{ item.name }}</div>
}
}
```
### 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
<!-- OLD -->
@if (loading()) {
<mat-spinner></mat-spinner>
}
<!-- NEW -->
@if (loading()) {
<app-loading-skeleton type="list"></app-loading-skeleton>
}
```
### 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