Refactor return search component and remove unused dropdown.

- 🛠️ **Refactor**: Updated return search result component for mobile responsiveness
- 🗑️ **Chore**: Removed unused order-by dropdown component and related files
- 📚 **Docs**: Enhanced component documentation for clarity
This commit is contained in:
Lorenz Hilpert
2025-04-11 15:24:08 +02:00
parent 3e14426d2e
commit 8144253a18
7 changed files with 469 additions and 109 deletions

View File

@@ -5,6 +5,186 @@
- **Readability First**: Write code that is easy to read and understand.
- **Consistency**: Follow the same patterns and conventions throughout the codebase.
- **Clean Code**: Avoid unnecessary complexity and keep functions small and focused.
- **SOLID Principles**: Follow SOLID design principles to create more maintainable, flexible, and scalable code.
## SOLID Design Principles
SOLID is an acronym for five design principles that help make software designs more understandable, flexible, and maintainable:
- **Single Responsibility Principle (SRP)**: A class should have only one reason to change, meaning it should have only one job or responsibility.
```typescript
// Good - Each class has a single responsibility
class UserAuthentication {
authenticate(username: string, password: string): boolean {
// Authentication logic
}
}
class UserRepository {
findById(id: string): User {
// Database access logic
}
}
// Bad - Class has multiple responsibilities
class UserManager {
authenticate(username: string, password: string): boolean {
// Authentication logic
}
findById(id: string): User {
// Database access logic
}
sendEmail(user: User, message: string): void {
// Email sending logic
}
}
```
- **Open/Closed Principle (OCP)**: Software entities should be open for extension but closed for modification.
```typescript
// Good - Open for extension
interface PaymentProcessor {
processPayment(amount: number): void;
}
class CreditCardProcessor implements PaymentProcessor {
processPayment(amount: number): void {
// Credit card processing logic
}
}
class PayPalProcessor implements PaymentProcessor {
processPayment(amount: number): void {
// PayPal processing logic
}
}
// New payment methods can be added without modifying existing code
```
- **Liskov Substitution Principle (LSP)**: Objects of a superclass should be replaceable with objects of subclasses without affecting the correctness of the program.
```typescript
// Good - Derived classes can substitute base class
class Rectangle {
constructor(
protected width: number,
protected height: number,
) {}
setWidth(width: number): void {
this.width = width;
}
setHeight(height: number): void {
this.height = height;
}
getArea(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
constructor(size: number) {
super(size, size);
}
// Preserve behavior when overriding methods
setWidth(width: number): void {
super.setWidth(width);
super.setHeight(width);
}
setHeight(height: number): void {
super.setWidth(height);
super.setHeight(height);
}
}
```
- **Interface Segregation Principle (ISP)**: Clients should not be forced to depend on interfaces they do not use.
```typescript
// Good - Segregated interfaces
interface Printable {
print(): void;
}
interface Scannable {
scan(): void;
}
class AllInOnePrinter implements Printable, Scannable {
print(): void {
// Printing logic
}
scan(): void {
// Scanning logic
}
}
class BasicPrinter implements Printable {
print(): void {
// Printing logic
}
}
// Bad - Fat interface
interface OfficeMachine {
print(): void;
scan(): void;
fax(): void;
staple(): void;
}
// Classes must implement methods they don't need
```
- **Dependency Inversion Principle (DIP)**: High-level modules should not depend on low-level modules. Both should depend on abstractions.
```typescript
// Good - Depending on abstractions
interface Logger {
log(message: string): void;
}
class ConsoleLogger implements Logger {
log(message: string): void {
console.log(message);
}
}
class FileLogger implements Logger {
log(message: string): void {
// File logging logic
}
}
class UserService {
constructor(private logger: Logger) {}
createUser(user: User): void {
// Create user logic
this.logger.log(`User created: ${user.name}`);
}
}
// The UserService depends on the abstraction (Logger interface)
// not on concrete implementations
```
Following these principles improves code quality by:
- Reducing coupling between components
- Making the system more modular and easier to maintain
- Facilitating testing and extension
- Promoting code reuse
## Extended Guidelines for Angular and TypeScript
@@ -13,16 +193,24 @@ This section extends the core code style principles with Angular-specific and ad
### Angular Enhancements
- **Change Detection**: Use the OnPush strategy by default for better performance.
- **Lifecycle Hooks**: Explicitly implement Angular lifecycle interfaces.
- **Lifecycle Hooks**: Explicitly implement Angular lifecycle interfaces (OnInit, OnDestroy, etc.).
- **Template Management**: Keep templates concise and use the async pipe to handle observables.
- **Component Structure**: Follow best practices for component modularization to enhance readability and testability.
- **Naming Conventions**: Follow Angular's official naming conventions for selectors, files, and component classes.
- **File Organization**: Structure files according to features and follow the recommended folder structure.
- **Control Flow**: Use modern control flow syntax (@if, @for) instead of structural directives (*ngIf, *ngFor).
- **Signals**: Prefer signals over RxJS for simpler state management within components.
### TypeScript Enhancements
- **Strict Type Checking**: Enable strict mode (`strict: true`) and avoid excessive use of `any`.
- **Interfaces vs. Types**: Prefer interfaces for object definitions and use type aliases for unions and intersections.
- **Generics**: Use meaningful type parameter names and constrain generics when applicable.
- **Documentation**: Employ JSDoc comments functions and generic parameters to improve code clarity.
- **Documentation**: Employ JSDoc comments for functions and generic parameters to improve code clarity.
- **Non-Nullability**: Use the non-null assertion operator (!) sparingly and only when you're certain a value cannot be null.
- **Type Guards**: Implement custom type guards to handle type narrowing safely.
- **Immutability**: Favor immutable data structures and use readonly modifiers when applicable.
- **Exhaustiveness Checking**: Use exhaustiveness checking for switch statements handling union types.
## TypeScript Guidelines
@@ -48,18 +236,18 @@ This section extends the core code style principles with Angular-specific and ad
- Prefer `interface` over `type` for object definitions
- Use `type` for unions, intersections, and mapped types
- Follow Angular's naming convention: `IComponentProps` for props interfaces
- Follow Angular's naming convention: Don't prefix interfaces with 'I' (use `ComponentProps` not `IComponentProps`)
- Extend interfaces instead of repeating properties
- Use readonly modifiers where appropriate
```typescript
// Good
interface IBaseProps {
interface BaseProps {
readonly id: string;
name: string;
}
interface IUserProps extends IBaseProps {
interface UserProps extends BaseProps {
email: string;
}
@@ -75,9 +263,49 @@ This section extends the core code style principles with Angular-specific and ad
- **Enums and Constants**:
- Use `const enum` for better performance
- Only use regular `enum` when runtime access is required
- Prefer union types for simple string literals
- Prefer this order of implementation (from most to least preferred):
1. `const enum` for better compile-time performance
2. Object literals with `as const` for runtime flexibility
3. Regular `enum` only when necessary for runtime access
- **When to use each approach**:
- Use `const enum` for internal application enumerations that don't need runtime access
- Use `const object as const` when values need to be inspected at runtime or exported in an API
- Use regular `enum` only when runtime enumeration object access is required
```typescript
// Good - const enum (preferred for most cases)
// Advantages: Tree-shakable, type-safe, disappears at compile time
export const enum ConstEnumStates {
NotSet = 'not-set',
Success = 'success',
}
// Good - const object with 'as const' assertion
// Advantages: Runtime accessible, works well with API boundaries
export const ConstStates = {
NotSet: 'not-set',
Success: 'success',
} as const;
// Types can be extracted from const objects
type ConstStatesType = (typeof ConstStates)[keyof typeof ConstStates];
// Least preferred - regular enum
// Only use when you need the enum object at runtime
export enum States {
NotSet = 'not-set',
Success = 'success',
}
```
- Use union types as an alternative for simple string literals
```typescript
// Alternative approach using union types
export type StatusType = 'not-set' | 'success';
```
- **Functions and Methods**:
@@ -94,7 +322,7 @@ This section extends the core code style principles with Angular-specific and ad
* @param id - The user's unique identifier
* @param includeDetails - Whether to include additional user details
*/
const getUser = (id: string, includeDetails = false): Promise<IUser> => {
const getUser = (id: string, includeDetails = false): Promise<User> => {
// ...implementation
};
@@ -113,12 +341,12 @@ Example:
```typescript
// Good
interface IUserProps {
interface UserProps {
id: string;
name: string;
}
interface IAdminProps extends IUserProps {
interface AdminProps extends UserProps {
permissions: string[];
}
@@ -127,7 +355,7 @@ const enum UserRole {
User = 'USER',
}
const getUser = <T extends IUserProps>(id: string): Promise<T> => {
const getUser = <T extends UserProps>(id: string): Promise<T> => {
// ...implementation
};
@@ -170,20 +398,116 @@ function getUser(id) {
subscription: Subscription;
ngOnInit() {
this.subscription = this.userService.getUsers().subscribe((users) => (this.users = users));
this.subscription = this.userService
.getUsers()
.subscribe((users) => (this.users = users));
}
}
```
- **Templates**
- **Templates and Control Flow**:
- Use new control flow syntax - instead if \*ngIf use the @if syntax
- Use modern control flow syntax (`@if`, `@for`, `@switch`) instead of structural directives (`*ngIf`, `*ngFor`, `*ngSwitch`).
```html
<!-- Good - Modern control flow syntax -->
<div>
@if (user) {
<h1>Welcome, {{ user.name }}!</h1>
} @else if (isLoading) {
<h1>Loading user data...</h1>
} @else {
<h1>Please log in</h1>
}
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>No items available</li>
}
</ul>
@switch (userRole) { @case ('admin') {
<app-admin-dashboard />
} @case ('manager') {
<app-manager-dashboard />
} @default {
<app-user-dashboard />
} }
</div>
<!-- Bad - Old structural directives -->
<div>
<h1 *ngIf="user">Welcome, {{ user.name }}!</h1>
<h1 *ngIf="!user && isLoading">Loading user data...</h1>
<h1 *ngIf="!user && !isLoading">Please log in</h1>
<ul>
<li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
<li *ngIf="!items || items.length === 0">No items available</li>
</ul>
<app-admin-dashboard *ngIf="userRole === 'admin'"></app-admin-dashboard>
<app-manager-dashboard
*ngIf="userRole === 'manager'"
></app-manager-dashboard>
<app-user-dashboard
*ngIf="userRole !== 'admin' && userRole !== 'manager'"
></app-user-dashboard>
</div>
```
- When using `@for`, always specify the `track` expression to optimize rendering performance:
- Use a unique identifier property (like `id` or `uuid`) when available
- Only use `$index` for static collections that never change
- Avoid using non-unique properties that could result in DOM mismatches
- Leverage contextual variables in `@for` blocks:
- `$index` - Current item index
- `$first` - Boolean indicating if this is the first item
- `$last` - Boolean indicating if this is the last item
- `$even` - Boolean indicating if this index is even
- `$odd` - Boolean indicating if this index is odd
- `$count` - Total number of items in the collection
```html
<!-- Good - Using contextual variables -->
@for (item of items; track item.id; let i = $index, isLast = $last) {
<li [class.last-item]="isLast">{{ i + 1 }}. {{ item.name }}</li>
}
```
- Use the `@empty` block with `@for` to handle empty collections gracefully
- Store conditional expression results in variables for clearer templates:
```html
<!-- Good - Storing expression result in variable -->
@if (user.permissions.canEditSettings; as canEdit) {
<button [disabled]="!canEdit">Edit Settings</button>
}
```
## Project-Specific Preferences
- **Frameworks**: Follow best practices for Nx, Hono, and Zod.
- **Frameworks**: Follow best practices for Nx, Angular, date-fns, Ngrx, RxJs and Zod.
- **Testing**: Use Jest with Spectator for unit tests and follow the Arrange-Act-Assert pattern.
- **File Naming**: Use kebab-case for filenames (e.g., `my-component.ts`).
- **File Naming**:
- Use kebab-case for filenames (e.g., `my-component.ts`).
- Follow a pattern that describes the symbol's feature then its type: `feature.type.ts`
```
// Good examples
user.service.ts
auth.guard.ts
product-list.component.ts
order.model.ts
// Bad examples
service-user.ts
userService.ts
```
- **Comments**: Use JSDoc for documenting functions, classes, and modules.
## Formatting
@@ -198,25 +522,10 @@ function getUser(id) {
- Use ESLint with the recommended TypeScript and Nx configurations.
- Prettier should be used for consistent formatting.
## Example
```typescript
// Good Example
interface User {
id: string;
name: string;
}
const getUser = (id: string): User => {
// ...function logic...
};
// Bad Example
function getUser(id) {
// ...function logic...
}
```
## References
- [Angular Style Guide](https://angular.dev/style-guide#)
- [Angular Style Guide](https://angular.dev/style-guide) - Official Angular style guide with best practices for Angular development
- [Angular Control Flow](https://angular.dev/guide/templates/control-flow) - Official Angular documentation on the new control flow syntax (@if, @for, @switch)
- [TypeScript Style Guide](https://ts.dev/style/) - TypeScript community style guide with patterns and practices
- [SOLID Design Principles](https://en.wikipedia.org/wiki/SOLID) - Wikipedia article explaining the SOLID principles in object-oriented design
- [Clean Code](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) - Robert C. Martin's seminal book on writing clean, maintainable code