Update .gitignore to exclude build-trace and bundle-report.json files. Revise package.json codegen script to clarify API types generation process. Enhance README with updated instructions for API client usage and automatic type generation. Remove outdated design and requirements documents related to codebase refactoring. Refactor InvoiceDetail components for improved UI consistency and user experience, including enhanced styling and layout adjustments.
This commit is contained in:
parent
a102f362e2
commit
22c860e07b
2
.gitignore
vendored
2
.gitignore
vendored
@ -131,6 +131,8 @@ temp/
|
|||||||
**/.next/
|
**/.next/
|
||||||
**/build/
|
**/build/
|
||||||
**/*.tsbuildinfo
|
**/*.tsbuildinfo
|
||||||
|
**/build-trace/
|
||||||
|
**/bundle-report.json
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
|||||||
@ -1,288 +0,0 @@
|
|||||||
# Codebase Refactoring Review Design Document
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This design document outlines the fixes and improvements needed to complete the codebase refactoring properly. Based on the review, several issues were identified that need to be addressed to achieve the clean, atomic design architecture originally specified.
|
|
||||||
|
|
||||||
## Issues Identified
|
|
||||||
|
|
||||||
### 1. Incomplete Atomic Design Implementation
|
|
||||||
|
|
||||||
**Problem**: Components are not properly categorized according to atomic design principles.
|
|
||||||
|
|
||||||
**Current State**:
|
|
||||||
|
|
||||||
- Catalog components are in `/components/catalog/` instead of being properly categorized
|
|
||||||
- Many components that should be molecules are mixed with atoms
|
|
||||||
- Business-specific components are in shared locations
|
|
||||||
|
|
||||||
**Solution**: Reorganize components into proper atomic design hierarchy:
|
|
||||||
|
|
||||||
```
|
|
||||||
components/
|
|
||||||
├── ui/ (Atoms - Basic building blocks)
|
|
||||||
│ ├── Button/
|
|
||||||
│ ├── Input/
|
|
||||||
│ ├── Badge/
|
|
||||||
│ └── LoadingSpinner/
|
|
||||||
├── common/ (Molecules - Combinations of atoms)
|
|
||||||
│ ├── DataTable/
|
|
||||||
│ ├── SearchBar/
|
|
||||||
│ ├── FormField/
|
|
||||||
│ └── StatusIndicator/
|
|
||||||
├── layout/ (Organisms - Complex UI sections)
|
|
||||||
│ ├── DashboardLayout/
|
|
||||||
│ ├── PageLayout/
|
|
||||||
│ └── AuthLayout/
|
|
||||||
└── business/ (Business-specific molecules)
|
|
||||||
├── ProductCard/
|
|
||||||
├── OrderSummary/
|
|
||||||
└── PricingDisplay/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Legacy Code and TODO Comments
|
|
||||||
|
|
||||||
**Problem**: Numerous TODO comments and legacy compatibility code remain.
|
|
||||||
|
|
||||||
**Current Issues**:
|
|
||||||
|
|
||||||
- Disabled exports with TODO comments in multiple index files
|
|
||||||
- Legacy compatibility exports in layout components
|
|
||||||
- Incomplete feature module implementations
|
|
||||||
- Deprecated component references
|
|
||||||
|
|
||||||
**Solution**: Clean up all legacy code and complete implementations.
|
|
||||||
|
|
||||||
### 3. Misplaced Business Components
|
|
||||||
|
|
||||||
**Problem**: Business-specific components are in shared locations.
|
|
||||||
|
|
||||||
**Current Issues**:
|
|
||||||
|
|
||||||
- Catalog components should be in the catalog feature module
|
|
||||||
- Product-specific components are in shared components directory
|
|
||||||
- Business logic mixed with presentation components
|
|
||||||
|
|
||||||
**Solution**: Move business components to appropriate feature modules.
|
|
||||||
|
|
||||||
### 4. Inconsistent Component Structure
|
|
||||||
|
|
||||||
**Problem**: Components don't follow consistent patterns.
|
|
||||||
|
|
||||||
**Current Issues**:
|
|
||||||
|
|
||||||
- Mixed file naming conventions
|
|
||||||
- Inconsistent folder structures
|
|
||||||
- Some components lack proper index files
|
|
||||||
- Export patterns are inconsistent
|
|
||||||
|
|
||||||
**Solution**: Standardize all component structures.
|
|
||||||
|
|
||||||
## Proposed Architecture Fixes
|
|
||||||
|
|
||||||
### Component Reorganization
|
|
||||||
|
|
||||||
#### Phase 1: Atomic Design Restructure
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Move catalog components to feature module
|
|
||||||
features/catalog/
|
|
||||||
├── components/
|
|
||||||
│ ├── ProductCard/
|
|
||||||
│ ├── ProductComparison/
|
|
||||||
│ ├── PricingDisplay/
|
|
||||||
│ ├── OrderSummary/
|
|
||||||
│ ├── ConfigurationStep/
|
|
||||||
│ └── index.ts
|
|
||||||
├── hooks/
|
|
||||||
├── services/
|
|
||||||
└── types/
|
|
||||||
|
|
||||||
// Keep only truly generic components in shared
|
|
||||||
components/common/
|
|
||||||
├── DataTable/
|
|
||||||
├── SearchBar/
|
|
||||||
├── FormField/
|
|
||||||
└── StatusIndicator/
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Phase 2: Clean Up Legacy Code
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Remove legacy exports
|
|
||||||
// Before:
|
|
||||||
export { DashboardLayout as default } from "./dashboard-layout";
|
|
||||||
export { PageLayout as LegacyPageLayout } from "./page-layout";
|
|
||||||
|
|
||||||
// After:
|
|
||||||
export { DashboardLayout } from "./DashboardLayout";
|
|
||||||
export { PageLayout } from "./PageLayout";
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Phase 3: Complete Feature Modules
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Complete feature module exports
|
|
||||||
// Before:
|
|
||||||
// Components - TODO: Enable when implemented
|
|
||||||
// export * from './components';
|
|
||||||
|
|
||||||
// After:
|
|
||||||
export * from "./components";
|
|
||||||
export * from "./hooks";
|
|
||||||
export * from "./services";
|
|
||||||
export * from "./types";
|
|
||||||
```
|
|
||||||
|
|
||||||
### Component Standards
|
|
||||||
|
|
||||||
#### Naming Conventions
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Component files: PascalCase
|
|
||||||
ProductCard.tsx
|
|
||||||
OrderSummary.tsx
|
|
||||||
|
|
||||||
// Folders: PascalCase for components
|
|
||||||
ProductCard/
|
|
||||||
├── ProductCard.tsx
|
|
||||||
├── ProductCard.test.tsx
|
|
||||||
├── ProductCard.stories.tsx
|
|
||||||
└── index.ts
|
|
||||||
|
|
||||||
// Utility files: kebab-case
|
|
||||||
form-validation.ts
|
|
||||||
api-client.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Export Patterns
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Component index files
|
|
||||||
export { ComponentName } from "./ComponentName";
|
|
||||||
export type { ComponentNameProps } from "./ComponentName";
|
|
||||||
|
|
||||||
// Feature index files
|
|
||||||
export * from "./components";
|
|
||||||
export * from "./hooks";
|
|
||||||
export * from "./services";
|
|
||||||
export * from "./types";
|
|
||||||
```
|
|
||||||
|
|
||||||
### File Structure Standards
|
|
||||||
|
|
||||||
#### Component Structure
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
ComponentName/
|
|
||||||
├── ComponentName.tsx # Main component
|
|
||||||
├── ComponentName.test.tsx # Unit tests
|
|
||||||
├── ComponentName.stories.tsx # Storybook stories (optional)
|
|
||||||
├── types.ts # Component-specific types (if complex)
|
|
||||||
└── index.ts # Exports
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Feature Module Structure
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
features/feature-name/
|
|
||||||
├── components/
|
|
||||||
│ ├── ComponentA/
|
|
||||||
│ ├── ComponentB/
|
|
||||||
│ └── index.ts
|
|
||||||
├── hooks/
|
|
||||||
│ ├── useFeature.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── services/
|
|
||||||
│ ├── feature.service.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── types/
|
|
||||||
│ ├── feature.types.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── utils/
|
|
||||||
│ ├── feature.utils.ts
|
|
||||||
│ └── index.ts
|
|
||||||
└── index.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation Strategy
|
|
||||||
|
|
||||||
### Step 1: Component Audit and Categorization
|
|
||||||
|
|
||||||
1. **Audit all components** and categorize them properly:
|
|
||||||
- **Atoms**: Basic UI elements (Button, Input, Badge)
|
|
||||||
- **Molecules**: Combinations of atoms (FormField, SearchBar)
|
|
||||||
- **Organisms**: Complex sections (Layouts, DataTable)
|
|
||||||
- **Business Components**: Feature-specific (ProductCard, OrderSummary)
|
|
||||||
|
|
||||||
2. **Create migration plan** for moving components to correct locations
|
|
||||||
|
|
||||||
### Step 2: Legacy Code Cleanup
|
|
||||||
|
|
||||||
1. **Remove all TODO comments** that represent incomplete work
|
|
||||||
2. **Complete or remove** disabled exports
|
|
||||||
3. **Remove legacy compatibility** code
|
|
||||||
4. **Standardize naming** conventions throughout
|
|
||||||
|
|
||||||
### Step 3: Feature Module Completion
|
|
||||||
|
|
||||||
1. **Move business components** to appropriate feature modules
|
|
||||||
2. **Complete feature module** implementations
|
|
||||||
3. **Ensure proper encapsulation** of business logic
|
|
||||||
4. **Create proper public APIs** for features
|
|
||||||
|
|
||||||
### Step 4: Component Standardization
|
|
||||||
|
|
||||||
1. **Standardize component structure** across all components
|
|
||||||
2. **Ensure consistent exports** and imports
|
|
||||||
3. **Add missing index files** where needed
|
|
||||||
4. **Update all import statements** to use new locations
|
|
||||||
|
|
||||||
### Step 5: Documentation and Testing
|
|
||||||
|
|
||||||
1. **Update component documentation**
|
|
||||||
2. **Ensure all components have proper TypeScript types**
|
|
||||||
3. **Add missing tests** for new component structure
|
|
||||||
4. **Update Storybook stories** if applicable
|
|
||||||
|
|
||||||
## Quality Assurance
|
|
||||||
|
|
||||||
### Validation Criteria
|
|
||||||
|
|
||||||
1. **No TODO comments** in production code
|
|
||||||
2. **No legacy compatibility** exports
|
|
||||||
3. **All components properly categorized** according to atomic design
|
|
||||||
4. **Consistent naming conventions** throughout
|
|
||||||
5. **Complete feature module** implementations
|
|
||||||
6. **Proper separation of concerns** between shared and business components
|
|
||||||
7. **All imports use new component locations**
|
|
||||||
8. **No duplicate or redundant components**
|
|
||||||
|
|
||||||
### Testing Strategy
|
|
||||||
|
|
||||||
1. **Component unit tests** for all refactored components
|
|
||||||
2. **Integration tests** for feature modules
|
|
||||||
3. **Visual regression tests** to ensure UI consistency
|
|
||||||
4. **Bundle size analysis** to ensure no bloat from refactoring
|
|
||||||
5. **Performance testing** to ensure no degradation
|
|
||||||
|
|
||||||
## Risk Mitigation
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
- **Gradual migration** of imports to new locations
|
|
||||||
- **Temporary compatibility** exports during transition
|
|
||||||
- **Comprehensive testing** before removing old components
|
|
||||||
|
|
||||||
### Performance Impact
|
|
||||||
|
|
||||||
- **Bundle analysis** to ensure tree-shaking works properly
|
|
||||||
- **Code splitting** verification for feature modules
|
|
||||||
- **Loading performance** monitoring during migration
|
|
||||||
|
|
||||||
### Developer Experience
|
|
||||||
|
|
||||||
- **Clear migration guide** for team members
|
|
||||||
- **Updated documentation** for new component locations
|
|
||||||
- **IDE support** for new import paths
|
|
||||||
- **Linting rules** to enforce new patterns
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
# Codebase Refactoring Review Requirements
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
This document outlines the requirements for reviewing and fixing the recent codebase refactoring to ensure it truly follows atomic design principles, has properly consolidated components, removed redundant legacy files, and achieved the clean architecture goals outlined in the original spec.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement 1
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want the atomic design structure to be properly implemented, so that components are correctly categorized and organized according to their complexity and reusability.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining the components directory THEN it SHALL have clear separation between atoms (ui/), molecules (common/), and organisms (layout/)
|
|
||||||
2. WHEN looking at catalog components THEN they SHALL be properly categorized as molecules or moved to appropriate feature modules
|
|
||||||
3. WHEN checking component exports THEN they SHALL be properly organized and not have disabled TODO comments
|
|
||||||
4. WHEN reviewing component structure THEN each component SHALL follow the established folder pattern with proper index files
|
|
||||||
5. IF components are in the wrong category THEN they SHALL be moved to the correct atomic design level
|
|
||||||
|
|
||||||
### Requirement 2
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want all legacy and duplicate components to be removed, so that the codebase is clean and maintainable without redundant code.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN searching for legacy components THEN there SHALL be no duplicate button, input, or loading implementations
|
|
||||||
2. WHEN examining layout components THEN legacy exports and backward compatibility code SHALL be removed
|
|
||||||
3. WHEN checking for deprecated components THEN they SHALL be completely removed from the codebase
|
|
||||||
4. WHEN looking at component imports THEN they SHALL all use the new centralized design system
|
|
||||||
5. IF legacy components exist THEN they SHALL be identified and removed completely
|
|
||||||
|
|
||||||
### Requirement 3
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want proper feature module organization, so that business logic is correctly encapsulated and feature boundaries are clear.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining feature modules THEN they SHALL have complete implementations, not just TODO placeholders
|
|
||||||
2. WHEN looking at catalog functionality THEN it SHALL be properly organized within the catalog feature module
|
|
||||||
3. WHEN checking feature exports THEN they SHALL expose complete APIs without disabled exports
|
|
||||||
4. WHEN reviewing component placement THEN business-specific components SHALL be in feature modules, not shared components
|
|
||||||
5. IF feature modules are incomplete THEN they SHALL be properly implemented or removed
|
|
||||||
|
|
||||||
### Requirement 4
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want consistent component structure and naming, so that the codebase follows established patterns throughout.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining component files THEN they SHALL follow consistent naming conventions (PascalCase for components, kebab-case for files)
|
|
||||||
2. WHEN looking at component organization THEN they SHALL have proper folder structure with index files
|
|
||||||
3. WHEN checking imports and exports THEN they SHALL be consistent and properly typed
|
|
||||||
4. WHEN reviewing file structure THEN there SHALL be no mixed naming patterns or inconsistent organization
|
|
||||||
5. IF naming inconsistencies exist THEN they SHALL be standardized according to the design system patterns
|
|
||||||
|
|
||||||
### Requirement 5
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want all TODO comments and incomplete implementations to be resolved, so that the refactoring is truly complete and production-ready.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN searching for TODO comments THEN critical functionality SHALL be implemented, not left as placeholders
|
|
||||||
2. WHEN examining disabled exports THEN they SHALL either be implemented or removed completely
|
|
||||||
3. WHEN looking at legacy compatibility code THEN it SHALL be removed after proper migration
|
|
||||||
4. WHEN checking component implementations THEN they SHALL be complete and functional
|
|
||||||
5. IF TODO items remain THEN they SHALL be either implemented or documented as future enhancements
|
|
||||||
|
|
||||||
### Requirement 6
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want proper separation of concerns between shared components and feature-specific components, so that the architecture is clean and maintainable.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining catalog components THEN business-specific ones SHALL be moved to the catalog feature module
|
|
||||||
2. WHEN looking at shared components THEN they SHALL only contain truly reusable, generic functionality
|
|
||||||
3. WHEN checking component dependencies THEN feature-specific logic SHALL not leak into shared components
|
|
||||||
4. WHEN reviewing component usage THEN shared components SHALL be used consistently across features
|
|
||||||
5. IF components are misplaced THEN they SHALL be moved to the appropriate location based on their purpose
|
|
||||||
|
|
||||||
### Requirement 7
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want the component library to be complete and properly exported, so that all components are easily discoverable and usable.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining the main components index THEN it SHALL export all available component categories
|
|
||||||
2. WHEN looking at UI component exports THEN they SHALL be complete and properly typed
|
|
||||||
3. WHEN checking layout component exports THEN they SHALL not have legacy compatibility exports
|
|
||||||
4. WHEN reviewing feature component exports THEN they SHALL be properly organized and accessible
|
|
||||||
5. IF component exports are incomplete THEN they SHALL be properly implemented and documented
|
|
||||||
|
|
||||||
### Requirement 8
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want consistent styling and theming implementation, so that the design system is properly applied throughout the application.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN examining component styles THEN they SHALL use the established design tokens and CSS custom properties
|
|
||||||
2. WHEN looking at component variants THEN they SHALL be implemented using class-variance-authority consistently
|
|
||||||
3. WHEN checking for hardcoded styles THEN they SHALL be replaced with design system tokens
|
|
||||||
4. WHEN reviewing responsive design THEN it SHALL use the established breakpoint system
|
|
||||||
5. IF styling inconsistencies exist THEN they SHALL be standardized to use the design system
|
|
||||||
@ -1,139 +0,0 @@
|
|||||||
# Codebase Refactoring Review Implementation Plan
|
|
||||||
|
|
||||||
- [x] 1. Audit and reorganize component structure according to atomic design
|
|
||||||
- Audit all components and categorize them properly (atoms, molecules, organisms, business)
|
|
||||||
- Create proper folder structure for each component category
|
|
||||||
- Move components to their correct atomic design locations
|
|
||||||
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_
|
|
||||||
|
|
||||||
- [x] 1.1 Reorganize UI components (Atoms)
|
|
||||||
- Ensure all basic UI components are properly structured in components/ui/
|
|
||||||
- Standardize component folder structure with proper index files
|
|
||||||
- Remove any business logic from atomic components
|
|
||||||
- _Requirements: 1.1, 1.2, 4.1, 4.2_
|
|
||||||
|
|
||||||
- [x] 1.2 Create and organize common components (Molecules)
|
|
||||||
- Move appropriate components from catalog to components/common/
|
|
||||||
- Create proper molecule components that combine atoms
|
|
||||||
- Ensure molecules are truly reusable across features
|
|
||||||
- _Requirements: 1.2, 6.1, 6.2, 6.3_
|
|
||||||
|
|
||||||
- [x] 1.3 Organize layout components (Organisms)
|
|
||||||
- Clean up layout component structure and remove legacy exports
|
|
||||||
- Ensure layout components are properly categorized as organisms
|
|
||||||
- Remove backward compatibility code from layout components
|
|
||||||
- _Requirements: 1.1, 2.2, 4.3_
|
|
||||||
|
|
||||||
- [x] 2. Move business-specific components to feature modules
|
|
||||||
- Move catalog components to features/catalog/components/
|
|
||||||
- Move subscription-specific components to features/subscriptions/components/
|
|
||||||
- Move billing-specific components to features/billing/components/
|
|
||||||
- _Requirements: 6.1, 6.2, 6.3, 6.4_
|
|
||||||
|
|
||||||
- [x] 2.1 Migrate catalog components to feature module
|
|
||||||
- Move ProductCard, ProductComparison, PricingDisplay to features/catalog/components/
|
|
||||||
- Move OrderSummary, ConfigurationStep, and related components to catalog feature
|
|
||||||
- Update all imports to use new catalog feature module locations
|
|
||||||
- _Requirements: 6.1, 6.2, 3.2_
|
|
||||||
|
|
||||||
- [x] 2.2 Complete catalog feature module implementation
|
|
||||||
- Implement proper hooks, services, and types for catalog feature
|
|
||||||
- Remove TODO comments and complete feature module exports
|
|
||||||
- Ensure catalog feature has complete public API
|
|
||||||
- _Requirements: 3.1, 3.2, 3.3, 5.1, 5.2_
|
|
||||||
|
|
||||||
- [x] 2.3 Migrate other business components to appropriate features
|
|
||||||
- Move subscription-specific components to subscriptions feature
|
|
||||||
- Move billing-specific components to billing feature
|
|
||||||
- Ensure proper encapsulation of business logic within features
|
|
||||||
- _Requirements: 6.1, 6.2, 6.3_
|
|
||||||
|
|
||||||
- [x] 3. Clean up legacy code and TODO comments
|
|
||||||
- Remove all legacy compatibility exports from layout components
|
|
||||||
- Complete or remove all TODO comments in component index files
|
|
||||||
- Remove deprecated component references and implementations
|
|
||||||
- _Requirements: 2.1, 2.2, 2.3, 5.1, 5.2_
|
|
||||||
|
|
||||||
- [x] 3.1 Remove legacy layout exports
|
|
||||||
- Remove legacy exports like "DashboardLayout as default" and "LegacyPageLayout"
|
|
||||||
- Update all imports to use new layout component names
|
|
||||||
- Remove backward compatibility code from layout index files
|
|
||||||
- _Requirements: 2.2, 2.3, 4.3_
|
|
||||||
|
|
||||||
- [x] 3.2 Complete disabled component exports
|
|
||||||
- Enable and implement all disabled exports in component index files
|
|
||||||
- Remove TODO comments from main components index file
|
|
||||||
- Complete common components implementation or remove placeholders
|
|
||||||
- _Requirements: 5.1, 5.2, 7.1, 7.2_
|
|
||||||
|
|
||||||
- [x] 3.3 Clean up feature module TODO comments
|
|
||||||
- Complete feature module implementations or remove placeholder exports
|
|
||||||
- Remove legacy hook exports and deprecated compatibility code
|
|
||||||
- Implement missing feature module functionality
|
|
||||||
- _Requirements: 3.1, 3.2, 5.1, 5.2_
|
|
||||||
|
|
||||||
- [x] 4. Standardize component structure and naming
|
|
||||||
- Ensure all components follow consistent PascalCase naming for files
|
|
||||||
- Standardize folder structure with proper index files for all components
|
|
||||||
- Fix any mixed naming patterns or inconsistent organization
|
|
||||||
- _Requirements: 4.1, 4.2, 4.3, 4.4_
|
|
||||||
|
|
||||||
- [x] 4.1 Standardize component file naming
|
|
||||||
- Ensure all component files use PascalCase naming (ProductCard.tsx)
|
|
||||||
- Ensure all utility files use kebab-case naming (form-validation.ts)
|
|
||||||
- Fix any inconsistent naming patterns throughout the codebase
|
|
||||||
- _Requirements: 4.1, 4.2_
|
|
||||||
|
|
||||||
- [x] 4.2 Standardize component folder structure
|
|
||||||
- Ensure all components have proper folder structure with index files
|
|
||||||
- Create missing index files for components that lack them
|
|
||||||
- Standardize export patterns across all component index files
|
|
||||||
- _Requirements: 4.2, 4.3, 7.3_
|
|
||||||
|
|
||||||
- [x] 4.3 Update import statements throughout codebase
|
|
||||||
- Update all imports to use new component locations after reorganization
|
|
||||||
- Ensure consistent import patterns using the centralized design system
|
|
||||||
- Remove any imports from old or deprecated component locations
|
|
||||||
- _Requirements: 2.4, 4.3, 7.4_
|
|
||||||
|
|
||||||
- [x] 5. Complete component library exports and documentation
|
|
||||||
- Enable all component category exports in main components index
|
|
||||||
- Ensure all UI components are properly exported with types
|
|
||||||
- Complete feature component exports and make them accessible
|
|
||||||
- _Requirements: 7.1, 7.2, 7.3, 7.4_
|
|
||||||
|
|
||||||
- [x] 5.1 Complete main components index exports
|
|
||||||
- Enable layout components export in main components index
|
|
||||||
- Enable common components export in main components index
|
|
||||||
- Remove TODO comments and complete component library exports
|
|
||||||
- _Requirements: 7.1, 7.2, 5.2_
|
|
||||||
|
|
||||||
- [x] 5.2 Ensure proper TypeScript types for all exports
|
|
||||||
- Add missing TypeScript interfaces for all component props
|
|
||||||
- Ensure all component exports include proper type exports
|
|
||||||
- Complete type definitions for feature module exports
|
|
||||||
- _Requirements: 7.2, 7.4, 4.4_
|
|
||||||
|
|
||||||
- [x] 6. Validate and test refactored structure
|
|
||||||
- Run comprehensive tests to ensure all components work after reorganization
|
|
||||||
- Verify that all imports resolve correctly after component moves
|
|
||||||
- Test that the atomic design structure is properly implemented
|
|
||||||
- _Requirements: 1.5, 2.5, 4.5, 6.5_
|
|
||||||
|
|
||||||
- [x] 6.1 Test component functionality after reorganization
|
|
||||||
- Run unit tests for all moved and refactored components
|
|
||||||
- Test that component props and functionality remain intact
|
|
||||||
- Verify that styling and theming work correctly after moves
|
|
||||||
- _Requirements: 8.1, 8.2, 8.3_
|
|
||||||
|
|
||||||
- [x] 6.2 Validate atomic design implementation
|
|
||||||
- Verify that atoms only contain basic UI elements without business logic
|
|
||||||
- Ensure molecules properly combine atoms and are reusable
|
|
||||||
- Confirm organisms are complex UI sections with proper composition
|
|
||||||
- _Requirements: 1.1, 1.2, 1.3, 6.3_
|
|
||||||
|
|
||||||
- [x] 6.3 Final cleanup and optimization
|
|
||||||
- Remove any unused files or components after reorganization
|
|
||||||
- Optimize imports and exports for better tree-shaking
|
|
||||||
- Run bundle analysis to ensure no performance regression
|
|
||||||
- _Requirements: 2.5, 5.5, 8.5_
|
|
||||||
@ -1,403 +0,0 @@
|
|||||||
# Design Document
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This design document outlines a comprehensive refactoring strategy to transform the current customer portal codebase into a modern, maintainable, and scalable architecture. The refactoring will eliminate redundancies, establish consistent patterns, and improve developer experience while maintaining existing functionality.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### High-Level Structure
|
|
||||||
|
|
||||||
The refactored architecture will follow a feature-driven, layered approach:
|
|
||||||
|
|
||||||
```
|
|
||||||
apps/portal/src/
|
|
||||||
├── app/ # Next.js App Router pages
|
|
||||||
├── components/ # Shared UI components (Design System)
|
|
||||||
│ ├── ui/ # Base UI components (atoms)
|
|
||||||
│ ├── layout/ # Layout components (organisms)
|
|
||||||
│ └── common/ # Shared business components (molecules)
|
|
||||||
├── features/ # Feature-specific modules
|
|
||||||
│ ├── auth/ # Authentication feature
|
|
||||||
│ ├── dashboard/ # Dashboard feature
|
|
||||||
│ ├── billing/ # Billing feature
|
|
||||||
│ ├── subscriptions/ # Subscriptions feature
|
|
||||||
│ ├── catalog/ # Product catalog feature
|
|
||||||
│ └── support/ # Support feature
|
|
||||||
├── lib/ # Core utilities and services
|
|
||||||
│ ├── api/ # API client and services
|
|
||||||
│ ├── auth/ # Authentication logic
|
|
||||||
│ ├── hooks/ # Shared React hooks
|
|
||||||
│ ├── stores/ # State management
|
|
||||||
│ ├── types/ # Shared TypeScript types
|
|
||||||
│ └── utils/ # Utility functions
|
|
||||||
├── providers/ # React context providers
|
|
||||||
└── styles/ # Global styles and design tokens
|
|
||||||
```
|
|
||||||
|
|
||||||
### Design Principles
|
|
||||||
|
|
||||||
1. **Feature-First Organization**: Group related functionality together
|
|
||||||
2. **Atomic Design**: Build UI components in a hierarchical manner
|
|
||||||
3. **Separation of Concerns**: Separate business logic from presentation
|
|
||||||
4. **Single Responsibility**: Each module has one clear purpose
|
|
||||||
5. **Dependency Inversion**: Depend on abstractions, not concretions
|
|
||||||
|
|
||||||
## Components and Interfaces
|
|
||||||
|
|
||||||
### Design System Architecture
|
|
||||||
|
|
||||||
#### Atomic Design Structure
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Base UI Components (Atoms)
|
|
||||||
components/ui/
|
|
||||||
├── Button/
|
|
||||||
│ ├── Button.tsx
|
|
||||||
│ ├── Button.stories.tsx
|
|
||||||
│ ├── Button.test.tsx
|
|
||||||
│ └── index.ts
|
|
||||||
├── Input/
|
|
||||||
├── Badge/
|
|
||||||
└── ...
|
|
||||||
|
|
||||||
// Composite Components (Molecules)
|
|
||||||
components/common/
|
|
||||||
├── DataTable/
|
|
||||||
├── SearchBar/
|
|
||||||
├── StatusIndicator/
|
|
||||||
└── ...
|
|
||||||
|
|
||||||
// Layout Components (Organisms)
|
|
||||||
components/layout/
|
|
||||||
├── DashboardLayout/
|
|
||||||
├── AuthLayout/
|
|
||||||
├── PageLayout/
|
|
||||||
└── ...
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Component Interface Standards
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Base component props interface
|
|
||||||
interface BaseComponentProps {
|
|
||||||
className?: string;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
testId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variant-based component pattern
|
|
||||||
interface ButtonProps extends BaseComponentProps {
|
|
||||||
variant?: "primary" | "secondary" | "outline" | "ghost";
|
|
||||||
size?: "sm" | "md" | "lg";
|
|
||||||
disabled?: boolean;
|
|
||||||
loading?: boolean;
|
|
||||||
onClick?: () => void;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Feature Module Structure
|
|
||||||
|
|
||||||
Each feature will follow a consistent internal structure:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
features/[feature-name]/
|
|
||||||
├── components/ # Feature-specific components
|
|
||||||
│ ├── [Component]/
|
|
||||||
│ │ ├── Component.tsx
|
|
||||||
│ │ ├── Component.test.tsx
|
|
||||||
│ │ └── index.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── hooks/ # Feature-specific hooks
|
|
||||||
│ ├── use[Feature].ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── services/ # Feature business logic
|
|
||||||
│ ├── [feature].service.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── types/ # Feature-specific types
|
|
||||||
│ ├── [feature].types.ts
|
|
||||||
│ └── index.ts
|
|
||||||
├── utils/ # Feature utilities
|
|
||||||
└── index.ts # Feature public API
|
|
||||||
```
|
|
||||||
|
|
||||||
### API Service Layer
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Centralized API service structure
|
|
||||||
lib/api/
|
|
||||||
├── client.ts # Base API client
|
|
||||||
├── types.ts # API response types
|
|
||||||
├── services/
|
|
||||||
│ ├── auth.service.ts
|
|
||||||
│ ├── billing.service.ts
|
|
||||||
│ ├── subscriptions.service.ts
|
|
||||||
│ └── index.ts
|
|
||||||
└── index.ts
|
|
||||||
|
|
||||||
// Service interface pattern
|
|
||||||
interface ApiService<T> {
|
|
||||||
getAll(params?: QueryParams): Promise<T[]>;
|
|
||||||
getById(id: string): Promise<T>;
|
|
||||||
create(data: CreateT): Promise<T>;
|
|
||||||
update(id: string, data: UpdateT): Promise<T>;
|
|
||||||
delete(id: string): Promise<void>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Data Models
|
|
||||||
|
|
||||||
### Centralized Type Definitions
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// lib/types/index.ts - Centralized type exports
|
|
||||||
export * from "./api.types";
|
|
||||||
export * from "./auth.types";
|
|
||||||
export * from "./billing.types";
|
|
||||||
export * from "./subscription.types";
|
|
||||||
export * from "./common.types";
|
|
||||||
|
|
||||||
// Common base types
|
|
||||||
interface BaseEntity {
|
|
||||||
id: string;
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginatedResponse<T> {
|
|
||||||
data: T[];
|
|
||||||
pagination: {
|
|
||||||
page: number;
|
|
||||||
limit: number;
|
|
||||||
total: number;
|
|
||||||
totalPages: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feature-specific type extensions
|
|
||||||
interface Subscription extends BaseEntity {
|
|
||||||
userId: string;
|
|
||||||
planId: string;
|
|
||||||
status: SubscriptionStatus;
|
|
||||||
// ... other properties
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### State Management Pattern
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Zustand store pattern for each feature
|
|
||||||
interface FeatureStore {
|
|
||||||
// State
|
|
||||||
data: FeatureData[];
|
|
||||||
loading: boolean;
|
|
||||||
error: string | null;
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
fetchData: () => Promise<void>;
|
|
||||||
updateItem: (id: string, data: Partial<FeatureData>) => Promise<void>;
|
|
||||||
reset: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// React Query integration for server state
|
|
||||||
const useFeatureQuery = (params?: QueryParams) => {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ["feature", params],
|
|
||||||
queryFn: () => featureService.getAll(params),
|
|
||||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
||||||
});
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
### Centralized Error Management
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// lib/errors/index.ts
|
|
||||||
export class AppError extends Error {
|
|
||||||
constructor(
|
|
||||||
message: string,
|
|
||||||
public code: string,
|
|
||||||
public statusCode?: number
|
|
||||||
) {
|
|
||||||
super(message);
|
|
||||||
this.name = "AppError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error boundary component
|
|
||||||
export function ErrorBoundary({ children }: { children: React.ReactNode }) {
|
|
||||||
// Implementation with error logging and user-friendly fallbacks
|
|
||||||
}
|
|
||||||
|
|
||||||
// API error handling
|
|
||||||
export function handleApiError(error: unknown): AppError {
|
|
||||||
if (error instanceof ApiError) {
|
|
||||||
return new AppError(error.message, error.code, error.status);
|
|
||||||
}
|
|
||||||
return new AppError("An unexpected error occurred", "UNKNOWN_ERROR");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Error Display Strategy
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Consistent error display components
|
|
||||||
interface ErrorStateProps {
|
|
||||||
error: AppError;
|
|
||||||
onRetry?: () => void;
|
|
||||||
variant?: "page" | "inline" | "toast";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ErrorState({ error, onRetry, variant = "page" }: ErrorStateProps) {
|
|
||||||
// Render appropriate error UI based on variant
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Testing Architecture
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Test utilities and setup
|
|
||||||
__tests__/
|
|
||||||
├── setup.ts # Test environment setup
|
|
||||||
├── utils/
|
|
||||||
│ ├── render.tsx # Custom render with providers
|
|
||||||
│ ├── mocks/ # API and service mocks
|
|
||||||
│ └── factories/ # Test data factories
|
|
||||||
└── fixtures/ # Test data fixtures
|
|
||||||
|
|
||||||
// Component testing pattern
|
|
||||||
describe('Button Component', () => {
|
|
||||||
it('renders with correct variant styles', () => {
|
|
||||||
render(<Button variant="primary">Click me</Button>);
|
|
||||||
expect(screen.getByRole('button')).toHaveClass('bg-blue-600');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles click events', async () => {
|
|
||||||
const handleClick = jest.fn();
|
|
||||||
render(<Button onClick={handleClick}>Click me</Button>);
|
|
||||||
|
|
||||||
await user.click(screen.getByRole('button'));
|
|
||||||
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Integration Testing
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Feature integration tests
|
|
||||||
describe('Dashboard Feature', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// Setup mocks and test data
|
|
||||||
mockApiService.dashboard.getSummary.mockResolvedValue(mockDashboardData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays user dashboard with correct data', async () => {
|
|
||||||
render(<DashboardPage />);
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByText('Active Subscriptions')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('3')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Optimization
|
|
||||||
|
|
||||||
### Code Splitting Strategy
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Feature-based code splitting
|
|
||||||
const DashboardPage = lazy(() => import("@/features/dashboard/pages/DashboardPage"));
|
|
||||||
const BillingPage = lazy(() => import("@/features/billing/pages/BillingPage"));
|
|
||||||
|
|
||||||
// Component-level splitting for heavy components
|
|
||||||
const DataVisualization = lazy(() => import("@/components/common/DataVisualization"));
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bundle Optimization
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Tree-shakeable exports
|
|
||||||
// Instead of: export * from './components';
|
|
||||||
// Use specific exports:
|
|
||||||
export { Button } from "./Button";
|
|
||||||
export { Input } from "./Input";
|
|
||||||
export type { ButtonProps, InputProps } from "./types";
|
|
||||||
|
|
||||||
// Dynamic imports for heavy dependencies
|
|
||||||
const heavyLibrary = await import("heavy-library");
|
|
||||||
```
|
|
||||||
|
|
||||||
### Caching Strategy
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// React Query configuration
|
|
||||||
const queryClient = new QueryClient({
|
|
||||||
defaultOptions: {
|
|
||||||
queries: {
|
|
||||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
||||||
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
||||||
retry: (failureCount, error) => {
|
|
||||||
if (error.status === 404) return false;
|
|
||||||
return failureCount < 3;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration Strategy
|
|
||||||
|
|
||||||
### Phase 1: Foundation (Weeks 1-2)
|
|
||||||
|
|
||||||
- Set up new folder structure
|
|
||||||
- Create base UI components (Button, Input, etc.)
|
|
||||||
- Establish design tokens and styling system
|
|
||||||
- Set up centralized API client
|
|
||||||
|
|
||||||
### Phase 2: Core Features (Weeks 3-4)
|
|
||||||
|
|
||||||
- Refactor authentication module
|
|
||||||
- Migrate dashboard feature
|
|
||||||
- Consolidate layout components
|
|
||||||
- Implement error handling system
|
|
||||||
|
|
||||||
### Phase 3: Business Features (Weeks 5-6)
|
|
||||||
|
|
||||||
- Migrate billing feature
|
|
||||||
- Refactor subscriptions feature
|
|
||||||
- Consolidate catalog functionality
|
|
||||||
- Implement testing framework
|
|
||||||
|
|
||||||
### Phase 4: Optimization (Weeks 7-8)
|
|
||||||
|
|
||||||
- Performance optimization
|
|
||||||
- Bundle analysis and splitting
|
|
||||||
- Documentation and cleanup
|
|
||||||
- Final testing and validation
|
|
||||||
|
|
||||||
## Risk Mitigation
|
|
||||||
|
|
||||||
### Backward Compatibility
|
|
||||||
|
|
||||||
- Maintain existing API contracts during migration
|
|
||||||
- Use feature flags for gradual rollout
|
|
||||||
- Keep old components until migration is complete
|
|
||||||
|
|
||||||
### Testing Coverage
|
|
||||||
|
|
||||||
- Maintain existing functionality through comprehensive testing
|
|
||||||
- Implement visual regression testing
|
|
||||||
- Set up automated testing pipeline
|
|
||||||
|
|
||||||
### Performance Monitoring
|
|
||||||
|
|
||||||
- Implement bundle size monitoring
|
|
||||||
- Set up performance metrics tracking
|
|
||||||
- Monitor Core Web Vitals during migration
|
|
||||||
@ -1,113 +0,0 @@
|
|||||||
# Requirements Document
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
This document outlines the requirements for refactoring the customer portal codebase to eliminate redundancies, improve maintainability, and create a modern, optimal structure. The current codebase has significant structural issues including duplicate components, inconsistent patterns, scattered business logic, and poor separation of concerns.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement 1
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want a clean component architecture, so that I can easily maintain and extend the codebase without duplicating functionality.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN components are created THEN they SHALL follow a consistent atomic design pattern (atoms, molecules, organisms)
|
|
||||||
2. WHEN UI components are needed THEN they SHALL be reused from a centralized design system
|
|
||||||
3. WHEN business logic is implemented THEN it SHALL be separated from presentation components
|
|
||||||
4. WHEN similar functionality exists THEN it SHALL be consolidated into reusable components
|
|
||||||
5. IF a component handles both UI and business logic THEN it SHALL be split into separate concerns
|
|
||||||
|
|
||||||
### Requirement 2
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want consistent page layouts and routing patterns, so that the application has a predictable structure and user experience.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN pages are created THEN they SHALL use standardized layout components
|
|
||||||
2. WHEN routing is implemented THEN it SHALL follow consistent naming conventions
|
|
||||||
3. WHEN page components are built THEN they SHALL separate data fetching from presentation
|
|
||||||
4. WHEN similar pages exist THEN they SHALL share common layout and behavior patterns
|
|
||||||
5. IF pages have duplicate functionality THEN they SHALL be consolidated or abstracted
|
|
||||||
|
|
||||||
### Requirement 3
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want centralized state management and data fetching, so that application state is predictable and API calls are optimized.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN data is fetched THEN it SHALL use centralized API services
|
|
||||||
2. WHEN state is managed THEN it SHALL follow consistent patterns across the application
|
|
||||||
3. WHEN API calls are made THEN they SHALL be cached and optimized to prevent redundant requests
|
|
||||||
4. WHEN business logic is implemented THEN it SHALL be encapsulated in service layers
|
|
||||||
5. IF duplicate API calls exist THEN they SHALL be consolidated into shared hooks or services
|
|
||||||
|
|
||||||
### Requirement 4
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want a modular feature-based architecture, so that related functionality is grouped together and easily maintainable.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN features are implemented THEN they SHALL be organized in self-contained modules
|
|
||||||
2. WHEN components belong to a feature THEN they SHALL be co-located with related business logic
|
|
||||||
3. WHEN shared functionality is needed THEN it SHALL be extracted to common utilities
|
|
||||||
4. WHEN features interact THEN they SHALL use well-defined interfaces
|
|
||||||
5. IF feature boundaries are unclear THEN they SHALL be clearly defined and documented
|
|
||||||
|
|
||||||
### Requirement 5
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want consistent TypeScript types and interfaces, so that the codebase is type-safe and self-documenting.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN types are defined THEN they SHALL be centralized and reusable
|
|
||||||
2. WHEN API responses are handled THEN they SHALL have corresponding TypeScript interfaces
|
|
||||||
3. WHEN components accept props THEN they SHALL have properly typed interfaces
|
|
||||||
4. WHEN business entities are used THEN they SHALL have consistent type definitions
|
|
||||||
5. IF duplicate types exist THEN they SHALL be consolidated into shared type definitions
|
|
||||||
|
|
||||||
### Requirement 6
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want optimized build performance and bundle size, so that the application loads quickly and development is efficient.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN components are imported THEN they SHALL support tree-shaking and code splitting
|
|
||||||
2. WHEN dependencies are added THEN they SHALL be evaluated for bundle size impact
|
|
||||||
3. WHEN code is bundled THEN it SHALL be optimized for production deployment
|
|
||||||
4. WHEN development builds run THEN they SHALL have fast hot-reload capabilities
|
|
||||||
5. IF unused code exists THEN it SHALL be identified and removed
|
|
||||||
|
|
||||||
### Requirement 7
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want consistent styling and theming, so that the UI is cohesive and maintainable.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN styles are applied THEN they SHALL use a consistent design token system
|
|
||||||
2. WHEN components are styled THEN they SHALL follow established design patterns
|
|
||||||
3. WHEN themes are implemented THEN they SHALL be centrally managed
|
|
||||||
4. WHEN CSS is written THEN it SHALL follow naming conventions and be scoped appropriately
|
|
||||||
5. IF duplicate styles exist THEN they SHALL be consolidated into reusable classes or components
|
|
||||||
|
|
||||||
### Requirement 8
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want improved testing capabilities, so that the codebase is reliable and regressions are prevented.
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN components are created THEN they SHALL be designed for testability
|
|
||||||
2. WHEN business logic is implemented THEN it SHALL be unit testable
|
|
||||||
3. WHEN API integrations are built THEN they SHALL be mockable for testing
|
|
||||||
4. WHEN user interactions are implemented THEN they SHALL be integration testable
|
|
||||||
5. IF testing utilities are needed THEN they SHALL be centralized and reusable
|
|
||||||
|
|
||||||
### Requirement 9
|
|
||||||
|
|
||||||
**User Story:** As a developer, I want the existing business logic to be intact and the core business logics should not be changed
|
|
||||||
|
|
||||||
#### Acceptance Criteria
|
|
||||||
|
|
||||||
1. WHEN redisning or refactoring always check the existing implementation and do not miss out on their business logic
|
|
||||||
2. WHEN business logic is implemented THEN it SHALL follow a similar way to the original logic
|
|
||||||
3. WHEN API integrations are built THEN they SHALL follow our business logic
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
# Implementation Plan
|
|
||||||
|
|
||||||
- [x] 1. Set up foundation and core infrastructure
|
|
||||||
- Create new folder structure following the feature-driven architecture
|
|
||||||
- Set up design tokens and CSS custom properties for consistent theming
|
|
||||||
- Implement base TypeScript configuration with strict type checking
|
|
||||||
- _Requirements: 1.1, 1.2, 5.1, 7.1_
|
|
||||||
|
|
||||||
- [x] 1.1 Create centralized type definitions
|
|
||||||
- Write shared TypeScript interfaces for API responses, entities, and common types
|
|
||||||
- Create base entity interfaces and pagination types
|
|
||||||
- Implement type utilities for form validation and API contracts
|
|
||||||
- _Requirements: 5.1, 5.2, 5.5_
|
|
||||||
|
|
||||||
- [x] 1.2 Implement design system foundation
|
|
||||||
- Create CSS custom properties for colors, spacing, typography, and animations
|
|
||||||
- Write utility classes for consistent spacing and layout patterns
|
|
||||||
- Implement responsive design tokens and breakpoint system
|
|
||||||
- _Requirements: 7.1, 7.2, 7.5_
|
|
||||||
|
|
||||||
- [x] 2. Build atomic UI component library
|
|
||||||
- Create base Button component with variants, sizes, and loading states
|
|
||||||
- Implement Input component with validation states and accessibility features
|
|
||||||
- Build Badge/StatusPill component to replace duplicate status indicators
|
|
||||||
- _Requirements: 1.1, 1.4, 7.2_
|
|
||||||
|
|
||||||
- [x] 2.1 Implement Button component system
|
|
||||||
- Write Button component with variant-based styling using class-variance-authority
|
|
||||||
- Add support for different sizes, states (loading, disabled), and as-prop polymorphism
|
|
||||||
- Create comprehensive test suite for Button component interactions
|
|
||||||
- _Requirements: 1.1, 1.3, 8.1_
|
|
||||||
|
|
||||||
- [x] 2.2 Create Input and form components
|
|
||||||
- Build Input component with validation states, icons, and accessibility labels
|
|
||||||
- Implement Label component with proper association and styling
|
|
||||||
- Create form validation utilities and error display components
|
|
||||||
- _Requirements: 1.1, 5.3, 8.1_
|
|
||||||
|
|
||||||
- [x] 2.3 Build status and feedback components
|
|
||||||
- Consolidate StatusPill/Badge components to replace scattered status indicators
|
|
||||||
- Create LoadingSpinner component to replace multiple loading implementations
|
|
||||||
- Implement ErrorState and EmptyState components for consistent feedback
|
|
||||||
- _Requirements: 1.4, 1.5, 7.2_
|
|
||||||
|
|
||||||
- [x] 3. Refactor API client and service layer
|
|
||||||
- Consolidate API client configuration and error handling
|
|
||||||
- Create service classes for each business domain (auth, billing, subscriptions)
|
|
||||||
- Implement consistent error handling and response type definitions
|
|
||||||
- _Requirements: 3.1, 3.4, 5.2_
|
|
||||||
|
|
||||||
- [x] 3.1 Build centralized API client
|
|
||||||
- Refactor existing API client to use consistent error handling and type safety
|
|
||||||
- Implement request/response interceptors for authentication and logging
|
|
||||||
- Create base service class with common CRUD operations
|
|
||||||
- _Requirements: 3.1, 3.3, 5.2_
|
|
||||||
|
|
||||||
- [x] 3.2 Create domain-specific API services
|
|
||||||
- Write AuthService class with login, signup, and session management methods
|
|
||||||
- Implement BillingService for invoice and payment operations
|
|
||||||
- Create SubscriptionService for subscription management and SIM operations
|
|
||||||
- _Requirements: 3.4, 4.1, 5.2_
|
|
||||||
|
|
||||||
- [x] 4. Implement layout component system
|
|
||||||
- Create DashboardLayout component consolidating navigation and sidebar logic
|
|
||||||
- Build PageLayout component for consistent page headers and breadcrumbs
|
|
||||||
- Implement AuthLayout for authentication pages with consistent styling
|
|
||||||
- _Requirements: 2.1, 2.4, 4.2_
|
|
||||||
|
|
||||||
- [x] 4.1 Build DashboardLayout component
|
|
||||||
- Consolidate navigation logic from existing layout components
|
|
||||||
- Implement responsive sidebar with proper mobile navigation
|
|
||||||
- Add user menu, notifications, and session timeout handling
|
|
||||||
- _Requirements: 2.1, 2.3, 4.2_
|
|
||||||
|
|
||||||
- [x] 4.2 Create PageLayout component
|
|
||||||
- Build reusable page header with title, description, and action buttons
|
|
||||||
- Implement breadcrumb navigation system
|
|
||||||
- Add loading and error states for page-level feedback
|
|
||||||
- _Requirements: 2.1, 2.4, 1.4_
|
|
||||||
|
|
||||||
- [x] 5. Refactor authentication feature module
|
|
||||||
- Consolidate auth store and API calls into cohesive auth feature
|
|
||||||
- Create reusable auth forms (login, signup, password reset) with shared validation
|
|
||||||
- Implement session management and token refresh logic
|
|
||||||
- _Requirements: 4.1, 4.2, 3.2_
|
|
||||||
|
|
||||||
- [x] 5.1 Consolidate authentication state management
|
|
||||||
- Refactor useAuthStore to use consistent patterns and error handling
|
|
||||||
- Implement token refresh logic and session timeout detection
|
|
||||||
- Create auth guards and route protection utilities
|
|
||||||
- _Requirements: 3.2, 4.1, 4.4_
|
|
||||||
|
|
||||||
- [x] 5.2 Build reusable authentication forms
|
|
||||||
- Create LoginForm component consolidating login page logic
|
|
||||||
- Implement SignupForm with multi-step validation and progress indication
|
|
||||||
- Build PasswordResetForm and SetPasswordForm components
|
|
||||||
- _Requirements: 1.4, 2.4, 5.3_
|
|
||||||
|
|
||||||
- [x] 6. Migrate dashboard feature to new architecture
|
|
||||||
- Refactor dashboard components to use new design system
|
|
||||||
- Consolidate dashboard data fetching and state management
|
|
||||||
- Implement dashboard widgets as reusable components
|
|
||||||
- _Requirements: 4.1, 4.2, 1.4_
|
|
||||||
|
|
||||||
- [x] 6.1 Refactor dashboard data layer
|
|
||||||
- Consolidate useDashboardSummary hook with proper error handling and caching
|
|
||||||
- Create dashboard service for API calls and data transformation
|
|
||||||
- Implement dashboard state management with loading and error states
|
|
||||||
- _Requirements: 3.1, 3.3, 4.1_
|
|
||||||
|
|
||||||
- [x] 6.2 Build dashboard UI components
|
|
||||||
- Refactor StatCard component to use new design system
|
|
||||||
- Create QuickAction component for dashboard shortcuts
|
|
||||||
- Implement ActivityFeed component for recent activity display
|
|
||||||
- _Requirements: 1.1, 1.4, 7.2_
|
|
||||||
|
|
||||||
- [x] 7. Consolidate billing feature components
|
|
||||||
- Merge duplicate invoice and payment components
|
|
||||||
- Create reusable billing data table with sorting and filtering
|
|
||||||
- Implement consistent billing status indicators and formatting
|
|
||||||
- _Requirements: 1.4, 1.5, 4.1_
|
|
||||||
|
|
||||||
- [x] 7.1 Build billing data components
|
|
||||||
- Create InvoiceTable component consolidating invoice list functionality
|
|
||||||
- Implement PaymentMethodCard for consistent payment method display
|
|
||||||
- Build BillingStatusBadge to replace scattered status indicators
|
|
||||||
- _Requirements: 1.4, 2.4, 7.2_
|
|
||||||
|
|
||||||
- [x] 7.2 Refactor billing pages
|
|
||||||
- Consolidate invoice pages to use shared components and layouts
|
|
||||||
- Implement payment method management with consistent form patterns
|
|
||||||
- Create billing summary components for dashboard integration
|
|
||||||
- _Requirements: 2.1, 2.4, 4.2_
|
|
||||||
|
|
||||||
- [x] 8. Refactor subscriptions and SIM management
|
|
||||||
- Consolidate subscription list and detail components
|
|
||||||
- Create reusable SIM management components for different subscription types
|
|
||||||
- Implement subscription action components (cancel, upgrade, etc.)
|
|
||||||
- _Requirements: 1.4, 4.1, 4.2_
|
|
||||||
|
|
||||||
- [x] 8.1 Build subscription management components
|
|
||||||
- Create SubscriptionCard component for list and grid displays
|
|
||||||
- Implement SubscriptionDetails component with service-specific sections
|
|
||||||
- Build SubscriptionActions component for common subscription operations
|
|
||||||
- _Requirements: 1.4, 4.2, 7.2_
|
|
||||||
|
|
||||||
- [x] 8.2 Consolidate SIM management functionality
|
|
||||||
- Refactor SimManagementSection to use new component architecture
|
|
||||||
- Create SimDetailsCard and SimActions components with consistent styling
|
|
||||||
- Implement DataUsageChart component with proper loading and error states
|
|
||||||
- _Requirements: 1.4, 2.4, 4.2_
|
|
||||||
|
|
||||||
- [x] 9. Refactor catalog and ordering system
|
|
||||||
- Consolidate product catalog components across different service types
|
|
||||||
- Create reusable product configuration and ordering flow components
|
|
||||||
- Implement consistent pricing display and order summary components
|
|
||||||
- Make sure the design is good and not worse than the old implementation of catalog pages. Internet, Sim and VPN may have different steps and choices and levels because of their structure and do not lose current business logic because its very important how it gets the data and how it builds it etc.
|
|
||||||
- _Requirements: 1.4, 2.4, 4.1_
|
|
||||||
|
|
||||||
- [x] 9.1 Build product catalog components
|
|
||||||
- Create ProductCard component for consistent product display across catalogs
|
|
||||||
- Implement PricingDisplay component with currency formatting and feature lists
|
|
||||||
- Build ProductComparison component for side-by-side product comparison
|
|
||||||
- _Requirements: 1.4, 7.2, 4.2_
|
|
||||||
|
|
||||||
- [x] 9.2 Consolidate ordering flow components
|
|
||||||
- Create OrderSummary component for checkout and configuration pages
|
|
||||||
- Implement ConfigurationStep component for multi-step product configuration
|
|
||||||
- Build AddressForm and PaymentForm components for checkout process
|
|
||||||
- _Requirements: 2.4, 4.2, 5.3_
|
|
||||||
|
|
||||||
- [ ] 10. Implement comprehensive testing framework
|
|
||||||
- Set up testing utilities and custom render functions with providers
|
|
||||||
- Create test factories for generating mock data and API responses
|
|
||||||
- Write unit tests for all new components and services
|
|
||||||
- _Requirements: 8.1, 8.2, 8.5_
|
|
||||||
|
|
||||||
- [ ] 10.1 Set up testing infrastructure
|
|
||||||
- Configure Jest and React Testing Library with custom render utilities
|
|
||||||
- Create mock factories for API responses and component props
|
|
||||||
- Implement test utilities for user interactions and async operations
|
|
||||||
- _Requirements: 8.1, 8.3, 8.5_
|
|
||||||
|
|
||||||
- [ ] 10.2 Write component and integration tests
|
|
||||||
- Create unit tests for all UI components with interaction testing
|
|
||||||
- Implement integration tests for feature modules and page components
|
|
||||||
- Write API service tests with proper mocking and error scenarios
|
|
||||||
- _Requirements: 8.1, 8.2, 8.4_
|
|
||||||
|
|
||||||
- [x] 11. Optimize bundle size and performance
|
|
||||||
- Implement code splitting for feature modules and heavy components
|
|
||||||
- Analyze bundle size and remove unused dependencies
|
|
||||||
- Set up performance monitoring and Core Web Vitals tracking
|
|
||||||
- _Requirements: 6.1, 6.2, 6.5_
|
|
||||||
|
|
||||||
- [x] 11.1 Implement code splitting strategy
|
|
||||||
- Add dynamic imports for feature pages and heavy components
|
|
||||||
- Configure Next.js bundle analyzer and optimize chunk splitting
|
|
||||||
- Implement lazy loading for non-critical components and features
|
|
||||||
- _Requirements: 6.1, 6.3, 6.5_
|
|
||||||
|
|
||||||
- [x] 11.2 Performance optimization and monitoring
|
|
||||||
- Optimize React Query configuration for better caching and performance
|
|
||||||
- Implement image optimization and lazy loading for better Core Web Vitals
|
|
||||||
- Set up bundle size monitoring and performance regression detection
|
|
||||||
- _Requirements: 6.2, 6.3, 6.4_
|
|
||||||
|
|
||||||
- [x] 12. Migration and cleanup
|
|
||||||
- Gradually migrate existing pages to use new components and architecture
|
|
||||||
- Remove duplicate components and unused code
|
|
||||||
- Update imports and dependencies throughout the codebase
|
|
||||||
- _Requirements: 1.5, 6.5, 4.4_
|
|
||||||
|
|
||||||
- [x] 12.1 Execute component migration
|
|
||||||
- Replace old Button, Input, and layout components with new design system
|
|
||||||
- Update all pages to use new PageLayout and feature components
|
|
||||||
- Remove duplicate status indicators, loading spinners, and form components
|
|
||||||
- _Requirements: 1.4, 1.5, 2.4_
|
|
||||||
|
|
||||||
- [x] 12.2 Final cleanup and optimization
|
|
||||||
- Remove unused files, components, and dependencies
|
|
||||||
- Update all import statements to use new component locations
|
|
||||||
- Run final bundle analysis and performance testing
|
|
||||||
- _Requirements: 6.5, 1.5, 4.4_
|
|
||||||
19
README.md
19
README.md
@ -165,24 +165,23 @@ docker save -o portal-backend.latest.tar portal-backend:latest
|
|||||||
|
|
||||||
Upload the tar files in Plesk → Docker → Images → Upload, then deploy using `config/docker/compose-plesk.yaml` as a stack.
|
Upload the tar files in Plesk → Docker → Images → Upload, then deploy using `config/docker/compose-plesk.yaml` as a stack.
|
||||||
|
|
||||||
### API Client Codegen
|
### API Client
|
||||||
|
|
||||||
1. Generate OpenAPI spec from BFF:
|
The portal uses an integrated OpenAPI-based client with automatic type generation:
|
||||||
|
|
||||||
|
1. **Generate OpenAPI spec** from BFF (runs automatically on build):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm --filter @customer-portal/bff run openapi:gen
|
pnpm openapi:gen
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Generate types and client:
|
2. **Types are auto-generated** in `apps/portal/src/lib/api/__generated__/types.ts`
|
||||||
|
|
||||||
```bash
|
3. **Use the client** in Portal:
|
||||||
pnpm --filter @customer-portal/api-client run codegen && pnpm --filter @customer-portal/api-client build
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Use in Portal:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { createClient } from "@customer-portal/api-client";
|
import { apiClient } from "@/lib/api";
|
||||||
|
// Client includes CSRF protection, auth headers, and error handling
|
||||||
```
|
```
|
||||||
|
|
||||||
### Environment Configuration
|
### Environment Configuration
|
||||||
|
|||||||
@ -220,14 +220,15 @@ export class InvoicesController {
|
|||||||
throw new Error("WHMCS client mapping not found");
|
throw new Error("WHMCS client mapping not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ssoResult = await this.whmcsService.createSsoToken(
|
const ssoUrl = await this.whmcsService.whmcsSsoForInvoice(
|
||||||
mapping.whmcsClientId,
|
mapping.whmcsClientId,
|
||||||
invoiceId ? `index.php?rp=/invoice/${invoiceId}` : undefined
|
invoiceId,
|
||||||
|
target || "view"
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: ssoResult.url,
|
url: ssoUrl,
|
||||||
expiresAt: ssoResult.expiresAt,
|
expiresAt: new Date(Date.now() + 60000).toISOString(), // 60 seconds per WHMCS spec
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import type { Invoice } from "@customer-portal/domain";
|
import type { Invoice } from "@customer-portal/domain";
|
||||||
|
import { formatCurrency } from "@customer-portal/domain";
|
||||||
|
|
||||||
const formatDate = (dateString?: string) => {
|
const formatDate = (dateString?: string) => {
|
||||||
if (!dateString || dateString === "0000-00-00" || dateString === "0000-00-00 00:00:00")
|
if (!dateString || dateString === "0000-00-00" || dateString === "0000-00-00 00:00:00")
|
||||||
@ -45,33 +46,63 @@ export function InvoiceHeader(props: InvoiceHeaderProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-8 py-6 border-b border-gray-200">
|
<div className="relative bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 px-8 py-8">
|
||||||
<DetailHeader
|
{/* Background Pattern */}
|
||||||
title={`Invoice #${invoice.number}`}
|
<div className="absolute inset-0 bg-[url('data:image/svg+xml,%3Csvg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cg fill="%23ffffff" fill-opacity="0.03"%3E%3Ccircle cx="7" cy="7" r="1"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E')] opacity-50"></div>
|
||||||
status={{
|
|
||||||
label: invoice.status,
|
<div className="relative">
|
||||||
variant:
|
{/* Header Content */}
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6">
|
||||||
|
{/* Title and Status */}
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-center gap-4">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold text-white mb-2">
|
||||||
|
Invoice #{invoice.number}
|
||||||
|
</h1>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<span
|
||||||
|
className={`inline-flex items-center px-3 py-1.5 rounded-full text-sm font-semibold ${
|
||||||
invoice.status === "Paid"
|
invoice.status === "Paid"
|
||||||
? "success"
|
? "bg-emerald-100 text-emerald-800 border border-emerald-200"
|
||||||
: invoice.status === "Overdue"
|
: invoice.status === "Overdue"
|
||||||
? "error"
|
? "bg-red-100 text-red-800 border border-red-200"
|
||||||
: invoice.status === "Unpaid"
|
: invoice.status === "Unpaid"
|
||||||
? "warning"
|
? "bg-amber-100 text-amber-800 border border-amber-200"
|
||||||
: "neutral",
|
: "bg-slate-100 text-slate-800 border border-slate-200"
|
||||||
}}
|
}`}
|
||||||
actions={
|
>
|
||||||
<div className="flex flex-col sm:flex-row gap-2 min-w-0">
|
{invoice.status === "Paid" && (
|
||||||
|
<svg className="w-4 h-4 mr-1.5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
{invoice.status === "Overdue" && (
|
||||||
|
<svg className="w-4 h-4 mr-1.5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
{invoice.status}
|
||||||
|
</span>
|
||||||
|
<span className="text-slate-300 text-sm">
|
||||||
|
{formatCurrency(invoice.total, { currency: invoice.currency })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
|
<div className="flex flex-wrap gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={onDownload}
|
onClick={onDownload}
|
||||||
disabled={loadingDownload}
|
disabled={loadingDownload}
|
||||||
className="inline-flex items-center justify-center px-3 py-2 border border-gray-300 text-xs font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50 transition-colors whitespace-nowrap"
|
className="inline-flex items-center justify-center px-4 py-2.5 bg-white/10 backdrop-blur-sm border border-white/20 text-sm font-medium rounded-xl text-white hover:bg-white/20 disabled:opacity-50 transition-all duration-200 whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{loadingDownload ? (
|
{loadingDownload ? (
|
||||||
<Skeleton className="h-4 w-4 rounded-full mr-1.5" />
|
<Skeleton className="h-4 w-4 rounded-full mr-2" />
|
||||||
) : (
|
) : (
|
||||||
<ArrowDownTrayIcon className="h-3 w-3 mr-1.5" />
|
<ArrowDownTrayIcon className="h-4 w-4 mr-2" />
|
||||||
)}
|
)}
|
||||||
Download
|
Download PDF
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{(invoice.status === "Unpaid" || invoice.status === "Overdue") && (
|
{(invoice.status === "Unpaid" || invoice.status === "Overdue") && (
|
||||||
@ -79,23 +110,23 @@ export function InvoiceHeader(props: InvoiceHeaderProps) {
|
|||||||
<button
|
<button
|
||||||
onClick={onManagePaymentMethods}
|
onClick={onManagePaymentMethods}
|
||||||
disabled={loadingPaymentMethods}
|
disabled={loadingPaymentMethods}
|
||||||
className="inline-flex items-center justify-center px-3 py-2 border border-gray-300 text-xs font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50 transition-colors whitespace-nowrap"
|
className="inline-flex items-center justify-center px-4 py-2.5 bg-white/10 backdrop-blur-sm border border-white/20 text-sm font-medium rounded-xl text-white hover:bg-white/20 disabled:opacity-50 transition-all duration-200 whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{loadingPaymentMethods ? (
|
{loadingPaymentMethods ? (
|
||||||
<Skeleton className="h-4 w-4 rounded-full mr-1.5" />
|
<Skeleton className="h-4 w-4 rounded-full mr-2" />
|
||||||
) : (
|
) : (
|
||||||
<ServerIcon className="h-3 w-3 mr-1.5" />
|
<ServerIcon className="h-4 w-4 mr-2" />
|
||||||
)}
|
)}
|
||||||
Payment
|
Payment Methods
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={onPay}
|
onClick={onPay}
|
||||||
disabled={loadingPayment}
|
disabled={loadingPayment}
|
||||||
className={`inline-flex items-center justify-center px-5 py-2.5 border border-transparent text-sm font-semibold rounded-lg text-white transition-all duration-200 shadow-md whitespace-nowrap ${
|
className={`inline-flex items-center justify-center px-6 py-2.5 text-sm font-semibold rounded-xl text-white transition-all duration-200 shadow-lg whitespace-nowrap ${
|
||||||
invoice.status === "Overdue"
|
invoice.status === "Overdue"
|
||||||
? "bg-red-600 hover:bg-red-700 ring-2 ring-red-200 hover:ring-red-300"
|
? "bg-gradient-to-r from-red-500 to-red-600 hover:from-red-600 hover:to-red-700 shadow-red-500/25"
|
||||||
: "bg-blue-600 hover:bg-blue-700 hover:shadow-lg"
|
: "bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 shadow-blue-500/25"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{loadingPayment ? (
|
{loadingPayment ? (
|
||||||
@ -108,25 +139,27 @@ export function InvoiceHeader(props: InvoiceHeaderProps) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
meta={
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 text-sm">
|
{/* Meta Information */}
|
||||||
<div>
|
<div className="mt-6 pt-6 border-t border-white/10">
|
||||||
<span className="text-gray-500">Issued:</span>
|
<div className="flex flex-col sm:flex-row gap-6 text-sm">
|
||||||
<span className="ml-2 px-2.5 py-1 text-xs font-bold rounded-md bg-blue-100 text-blue-800 border border-blue-200">
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-slate-400">Issued:</span>
|
||||||
|
<span className="px-3 py-1.5 bg-white/10 backdrop-blur-sm rounded-lg text-white font-medium border border-white/20">
|
||||||
{formatDate(invoice.issuedAt)}
|
{formatDate(invoice.issuedAt)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{invoice.dueDate && (
|
{invoice.dueDate && (
|
||||||
<div>
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-gray-500">Due:</span>
|
<span className="text-slate-400">Due:</span>
|
||||||
<span
|
<span
|
||||||
className={`ml-2 px-2.5 py-1 text-xs font-bold rounded-md ${
|
className={`px-3 py-1.5 rounded-lg font-medium border ${
|
||||||
invoice.status === "Overdue"
|
invoice.status === "Overdue"
|
||||||
? "bg-red-100 text-red-800 border border-red-200"
|
? "bg-red-100 text-red-800 border-red-200"
|
||||||
: invoice.status === "Unpaid"
|
: invoice.status === "Unpaid"
|
||||||
? "bg-amber-100 text-amber-800 border border-amber-200"
|
? "bg-amber-100 text-amber-800 border-amber-200"
|
||||||
: "bg-gray-100 text-gray-700 border border-gray-200"
|
: "bg-white/10 backdrop-blur-sm text-white border-white/20"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{formatDate(invoice.dueDate)}
|
{formatDate(invoice.dueDate)}
|
||||||
@ -135,8 +168,8 @@ export function InvoiceHeader(props: InvoiceHeaderProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,25 +12,37 @@ interface InvoiceItemsProps {
|
|||||||
|
|
||||||
export function InvoiceItems({ items = [], currency }: InvoiceItemsProps) {
|
export function InvoiceItems({ items = [], currency }: InvoiceItemsProps) {
|
||||||
return (
|
return (
|
||||||
<SubCard title="Items & Services">
|
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
|
||||||
|
<div className="px-6 py-4 bg-slate-50 border-b border-slate-200">
|
||||||
|
<h3 className="text-lg font-semibold text-slate-900">Items & Services</h3>
|
||||||
|
</div>
|
||||||
|
<div className="p-6">
|
||||||
{items.length > 0 ? (
|
{items.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-4">
|
||||||
{items.map(item => (
|
{items.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={item.id}
|
key={item.id}
|
||||||
className="flex justify-between items-center py-2 border-b border-gray-100 last:border-b-0"
|
className={`flex justify-between items-start py-4 ${
|
||||||
|
index !== items.length - 1 ? 'border-b border-slate-100' : ''
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1 pr-4">
|
||||||
<div className="font-medium text-gray-900">{item.description}</div>
|
<div className="font-semibold text-slate-900 mb-1">{item.description}</div>
|
||||||
|
<div className="flex flex-wrap gap-3 text-sm text-slate-500">
|
||||||
{item.quantity && item.quantity > 1 && (
|
{item.quantity && item.quantity > 1 && (
|
||||||
<div className="text-sm text-gray-500">Quantity: {item.quantity}</div>
|
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||||
|
Qty: {item.quantity}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{item.serviceId && (
|
{item.serviceId && (
|
||||||
<div className="text-xs text-gray-400">Service ID: {item.serviceId}</div>
|
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-slate-100 text-slate-700">
|
||||||
|
Service: {item.serviceId}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<div className="font-medium text-gray-900">
|
<div className="text-xl font-bold text-slate-900">
|
||||||
{formatCurrency(item.amount || 0, { currency })}
|
{formatCurrency(item.amount || 0, { currency })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -38,9 +50,17 @@ export function InvoiceItems({ items = [], currency }: InvoiceItemsProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-sm text-gray-600">No items found on this invoice.</div>
|
<div className="text-center py-8">
|
||||||
|
<div className="text-slate-400 mb-2">
|
||||||
|
<svg className="w-12 h-12 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p className="text-slate-500">No items found on this invoice.</p>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</SubCard>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,35 +23,48 @@ export function InvoicePaymentActions({
|
|||||||
if (!canPay) return null;
|
if (!canPay) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="space-y-4">
|
||||||
<button
|
{/* Primary Payment Action */}
|
||||||
onClick={onManagePaymentMethods}
|
|
||||||
disabled={loadingPaymentMethods}
|
|
||||||
className="inline-flex items-center justify-center px-3 py-2 border border-gray-300 text-xs font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50 transition-colors whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{loadingPaymentMethods ? (
|
|
||||||
<Skeleton className="h-4 w-4 rounded-full mr-1.5" />
|
|
||||||
) : (
|
|
||||||
<ServerIcon className="h-3 w-3 mr-1.5" />
|
|
||||||
)}
|
|
||||||
Payment Methods
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
onClick={onPay}
|
onClick={onPay}
|
||||||
disabled={loadingPayment}
|
disabled={loadingPayment}
|
||||||
className={`inline-flex items-center justify-center px-5 py-2.5 border border-transparent text-sm font-semibold rounded-lg text-white transition-all duration-200 shadow-md whitespace-nowrap ${
|
className={`w-full inline-flex items-center justify-center px-6 py-4 text-base font-semibold rounded-2xl text-white transition-all duration-200 shadow-lg ${
|
||||||
status === "Overdue"
|
status === "Overdue"
|
||||||
? "bg-red-600 hover:bg-red-700 ring-2 ring-red-200 hover:ring-red-300"
|
? "bg-gradient-to-r from-red-500 to-red-600 hover:from-red-600 hover:to-red-700 shadow-red-500/25"
|
||||||
: "bg-blue-600 hover:bg-blue-700 hover:shadow-lg"
|
: "bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 shadow-blue-500/25"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{loadingPayment ? (
|
{loadingPayment ? (
|
||||||
|
<Skeleton className="h-5 w-5 rounded-full mr-3" />
|
||||||
|
) : (
|
||||||
|
<ArrowTopRightOnSquareIcon className="h-5 w-5 mr-3" />
|
||||||
|
)}
|
||||||
|
{status === "Overdue" ? "Pay Overdue Invoice" : "Pay Invoice Now"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Secondary Action */}
|
||||||
|
<button
|
||||||
|
onClick={onManagePaymentMethods}
|
||||||
|
disabled={loadingPaymentMethods}
|
||||||
|
className="w-full inline-flex items-center justify-center px-4 py-3 border-2 border-slate-200 text-sm font-medium rounded-xl text-slate-700 bg-white hover:bg-slate-50 hover:border-slate-300 disabled:opacity-50 transition-all duration-200"
|
||||||
|
>
|
||||||
|
{loadingPaymentMethods ? (
|
||||||
<Skeleton className="h-4 w-4 rounded-full mr-2" />
|
<Skeleton className="h-4 w-4 rounded-full mr-2" />
|
||||||
) : (
|
) : (
|
||||||
<ArrowTopRightOnSquareIcon className="h-4 w-4 mr-2" />
|
<ServerIcon className="h-4 w-4 mr-2" />
|
||||||
)}
|
)}
|
||||||
{status === "Overdue" ? "Pay Overdue" : "Pay Now"}
|
Manage Payment Methods
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Payment Info */}
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-sm text-slate-500">
|
||||||
|
{status === "Overdue"
|
||||||
|
? "This invoice is overdue. Please pay as soon as possible to avoid service interruption."
|
||||||
|
: "Secure payment processing with multiple payment options available."
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,29 +13,47 @@ interface InvoiceTotalsProps {
|
|||||||
|
|
||||||
export function InvoiceTotals({ subtotal, tax, total, currency }: InvoiceTotalsProps) {
|
export function InvoiceTotals({ subtotal, tax, total, currency }: InvoiceTotalsProps) {
|
||||||
const fmt = (amount: number) => formatCurrency(amount, { currency });
|
const fmt = (amount: number) => formatCurrency(amount, { currency });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubCard title="Totals">
|
<div className="bg-gradient-to-br from-slate-50 to-slate-100 rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
|
||||||
<div className="max-w-xs ml-auto">
|
<div className="px-6 py-4 bg-white border-b border-slate-200">
|
||||||
<div className="space-y-2">
|
<h3 className="text-lg font-semibold text-slate-900">Invoice Summary</h3>
|
||||||
<div className="flex justify-between text-sm text-gray-600">
|
|
||||||
<span>Subtotal</span>
|
|
||||||
<span className="font-medium">{fmt(subtotal)}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-6">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex justify-between items-center text-slate-600">
|
||||||
|
<span className="font-medium">Subtotal</span>
|
||||||
|
<span className="font-semibold text-slate-900">{fmt(subtotal)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{tax > 0 && (
|
{tax > 0 && (
|
||||||
<div className="flex justify-between text-sm text-gray-600">
|
<div className="flex justify-between items-center text-slate-600">
|
||||||
<span>Tax</span>
|
<span className="font-medium">Tax</span>
|
||||||
<span className="font-medium">{fmt(tax)}</span>
|
<span className="font-semibold text-slate-900">{fmt(tax)}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="border-t border-gray-300 pt-2 mt-2">
|
|
||||||
|
<div className="border-t border-slate-200 pt-4">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-base font-semibold text-gray-900">Total</span>
|
<span className="text-lg font-bold text-slate-900">Total Amount</span>
|
||||||
<span className="text-2xl font-bold text-gray-900">{fmt(total)}</span>
|
<div className="text-right">
|
||||||
|
<div className="text-3xl font-bold text-slate-900">{fmt(total)}</div>
|
||||||
|
<div className="text-sm text-slate-500 mt-1">
|
||||||
|
{currency.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Visual accent */}
|
||||||
|
<div className="mt-6 pt-4 border-t border-slate-200">
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<div className="h-1 w-16 bg-gradient-to-r from-blue-400 to-blue-600 rounded-full"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SubCard>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -128,18 +128,23 @@ export function InvoiceDetailContainer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-8">
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50/30 py-8">
|
||||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 md:px-8">
|
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="mb-6">
|
{/* Navigation */}
|
||||||
|
<div className="mb-8">
|
||||||
<Link
|
<Link
|
||||||
href="/billing/invoices"
|
href="/billing/invoices"
|
||||||
className="inline-flex items-center text-gray-600 hover:text-gray-900 transition-colors"
|
className="inline-flex items-center gap-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors group"
|
||||||
>
|
>
|
||||||
← Back to Invoices
|
<svg className="w-4 h-4 transition-transform group-hover:-translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
Back to Invoices
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white rounded-2xl shadow border">
|
{/* Main Invoice Card */}
|
||||||
|
<div className="bg-white/80 backdrop-blur-sm rounded-3xl shadow-xl border border-white/20 overflow-hidden">
|
||||||
<InvoiceHeader
|
<InvoiceHeader
|
||||||
invoice={invoice}
|
invoice={invoice}
|
||||||
loadingDownload={loadingDownload}
|
loadingDownload={loadingDownload}
|
||||||
@ -150,25 +155,39 @@ export function InvoiceDetailContainer() {
|
|||||||
onManagePaymentMethods={handleManagePaymentMethods}
|
onManagePaymentMethods={handleManagePaymentMethods}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Success Banner for Paid Invoices */}
|
||||||
{invoice.status === "Paid" && (
|
{invoice.status === "Paid" && (
|
||||||
<div className="px-8 mt-6 mx-8">
|
<div className="px-8 py-4 bg-gradient-to-r from-emerald-50 to-teal-50 border-b border-emerald-100">
|
||||||
<AlertBanner variant="success" title="Invoice Paid">
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<CheckCircleIcon className="w-6 h-6 text-emerald-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-semibold text-emerald-900">Payment Received</h3>
|
||||||
|
<p className="text-sm text-emerald-700">
|
||||||
Paid on {invoice.paidDate || invoice.issuedAt}
|
Paid on {invoice.paidDate || invoice.issuedAt}
|
||||||
</AlertBanner>
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="px-8 py-6 space-y-6">
|
{/* Content Grid */}
|
||||||
|
<div className="p-8">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||||
|
{/* Left Column - Items */}
|
||||||
|
<div className="lg:col-span-2 space-y-6">
|
||||||
<InvoiceItems items={invoice.items} currency={invoice.currency} />
|
<InvoiceItems items={invoice.items} currency={invoice.currency} />
|
||||||
<InvoiceTotals
|
|
||||||
subtotal={invoice.subtotal}
|
|
||||||
tax={invoice.tax}
|
|
||||||
total={invoice.total}
|
|
||||||
currency={invoice.currency}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
{/* Payment Section for Unpaid Invoices */}
|
||||||
{(invoice.status === "Unpaid" || invoice.status === "Overdue") && (
|
{(invoice.status === "Unpaid" || invoice.status === "Overdue") && (
|
||||||
<SubCard title="Payment">
|
<div className="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-2xl p-6 border border-blue-100">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<CreditCardIcon className="w-6 h-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold text-slate-900">Payment Options</h3>
|
||||||
|
</div>
|
||||||
<InvoicePaymentActions
|
<InvoicePaymentActions
|
||||||
status={invoice.status}
|
status={invoice.status}
|
||||||
onManagePaymentMethods={handleManagePaymentMethods}
|
onManagePaymentMethods={handleManagePaymentMethods}
|
||||||
@ -176,9 +195,23 @@ export function InvoiceDetailContainer() {
|
|||||||
loadingPaymentMethods={loadingPaymentMethods}
|
loadingPaymentMethods={loadingPaymentMethods}
|
||||||
loadingPayment={loadingPayment}
|
loadingPayment={loadingPayment}
|
||||||
/>
|
/>
|
||||||
</SubCard>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Right Column - Totals */}
|
||||||
|
<div className="lg:col-span-1">
|
||||||
|
<div className="sticky top-8">
|
||||||
|
<InvoiceTotals
|
||||||
|
subtotal={invoice.subtotal}
|
||||||
|
tax={invoice.tax}
|
||||||
|
total={invoice.total}
|
||||||
|
currency={invoice.currency}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
"dev:watch": "pnpm --parallel --filter @customer-portal/domain --filter @customer-portal/portal --filter @customer-portal/bff run dev",
|
"dev:watch": "pnpm --parallel --filter @customer-portal/domain --filter @customer-portal/portal --filter @customer-portal/bff run dev",
|
||||||
"plesk:images": "bash ./scripts/plesk/build-images.sh",
|
"plesk:images": "bash ./scripts/plesk/build-images.sh",
|
||||||
"openapi:gen": "pnpm --filter @customer-portal/bff run openapi:gen",
|
"openapi:gen": "pnpm --filter @customer-portal/bff run openapi:gen",
|
||||||
"codegen": "echo 'API client moved to portal/lib/api - run codegen from portal app'",
|
"codegen": "echo 'API types are auto-generated from OpenAPI spec in portal/lib/api'",
|
||||||
"postinstall": "pnpm openapi:gen && pnpm codegen || true"
|
"postinstall": "pnpm openapi:gen && pnpm codegen || true"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Script to migrate remaining getSalesforceFieldMap usages to SalesforceFieldMapService
|
|
||||||
|
|
||||||
echo "🔄 Migrating remaining field map usages..."
|
|
||||||
|
|
||||||
# Files that still need migration
|
|
||||||
FILES=(
|
|
||||||
"apps/bff/src/modules/orders/services/order-fulfillment-validator.service.ts"
|
|
||||||
"apps/bff/src/modules/orders/services/order-builder.service.ts"
|
|
||||||
"apps/bff/src/integrations/salesforce/salesforce.service.ts"
|
|
||||||
"apps/bff/src/modules/orders/services/order-fulfillment-orchestrator.service.ts"
|
|
||||||
"apps/bff/src/modules/orders/services/order-pricebook.service.ts"
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "⚠️ The following files still need manual migration:"
|
|
||||||
for file in "${FILES[@]}"; do
|
|
||||||
echo " - $file"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "📝 These files use getSalesforceFieldMap() and need to be updated to:"
|
|
||||||
echo " 1. Inject SalesforceFieldMapService in constructor"
|
|
||||||
echo " 2. Call this.fieldMapService.getFieldMap() instead"
|
|
||||||
echo " 3. Import CoreConfigModule in their respective modules"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🎯 After manual migration, the deprecated functions can be completely removed."
|
|
||||||
Loading…
x
Reference in New Issue
Block a user