8 changed files with 288 additions and 106 deletions
@ -0,0 +1,207 @@ |
|||||
|
# GiftedDialog Entity Types Refactoring |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
This refactoring simplifies the `GiftedDialog` component by replacing the complex `updateEntityTypes()` method with explicit props for entity types. This makes the component more declarative, reusable, and easier to understand. |
||||
|
|
||||
|
## Problem |
||||
|
|
||||
|
The original `updateEntityTypes()` method used multiple props (`showProjects`, `fromProjectId`, `toProjectId`, `recipientEntityTypeOverride`) to determine entity types through complex conditional logic: |
||||
|
|
||||
|
```typescript |
||||
|
updateEntityTypes() { |
||||
|
// Reset and set entity types based on current context |
||||
|
this.giverEntityType = "person"; |
||||
|
this.recipientEntityType = "person"; |
||||
|
|
||||
|
// If recipient entity type is explicitly overridden, use that |
||||
|
if (this.recipientEntityTypeOverride) { |
||||
|
this.recipientEntityType = this.recipientEntityTypeOverride; |
||||
|
} |
||||
|
|
||||
|
// Determine entity types based on current context |
||||
|
if (this.showProjects) { |
||||
|
// HomeView "Project" button or ProjectViewView "Given by This" |
||||
|
this.giverEntityType = "project"; |
||||
|
// Only override recipient if not already set by recipientEntityTypeOverride |
||||
|
if (!this.recipientEntityTypeOverride) { |
||||
|
this.recipientEntityType = "person"; |
||||
|
} |
||||
|
} else if (this.fromProjectId) { |
||||
|
// ProjectViewView "Given by This" button (project is giver) |
||||
|
this.giverEntityType = "project"; |
||||
|
// Only override recipient if not already set by recipientEntityTypeOverride |
||||
|
if (!this.recipientEntityTypeOverride) { |
||||
|
this.recipientEntityType = "person"; |
||||
|
} |
||||
|
} else if (this.toProjectId) { |
||||
|
// ProjectViewView "Given to This" button (project is recipient) |
||||
|
this.giverEntityType = "person"; |
||||
|
// Only override recipient if not already set by recipientEntityTypeOverride |
||||
|
if (!this.recipientEntityTypeOverride) { |
||||
|
this.recipientEntityType = "project"; |
||||
|
} |
||||
|
} else { |
||||
|
// HomeView "Person" button |
||||
|
this.giverEntityType = "person"; |
||||
|
// Only override recipient if not already set by recipientEntityTypeOverride |
||||
|
if (!this.recipientEntityTypeOverride) { |
||||
|
this.recipientEntityType = "person"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### Issues with the Original Approach |
||||
|
|
||||
|
1. **Complex Logic**: Nested conditionals that were hard to follow |
||||
|
2. **Tight Coupling**: Views needed to understand internal logic to set the right props |
||||
|
3. **Inflexible**: Adding new entity type combinations required modifying the method |
||||
|
4. **Unclear Intent**: The relationship between props and entity types was not obvious |
||||
|
|
||||
|
## Solution |
||||
|
|
||||
|
### 1. Explicit Props |
||||
|
|
||||
|
Replace the complex logic with explicit props: |
||||
|
|
||||
|
```typescript |
||||
|
@Prop({ default: "person" }) giverEntityType = "person" as "person" | "project"; |
||||
|
@Prop({ default: "person" }) recipientEntityType = "person" as "person" | "project"; |
||||
|
``` |
||||
|
|
||||
|
### 2. Simple Inline Logic |
||||
|
|
||||
|
Views now use simple inline logic to determine entity types: |
||||
|
|
||||
|
```vue |
||||
|
<!-- HomeView --> |
||||
|
<GiftedDialog |
||||
|
ref="giftedDialog" |
||||
|
:giver-entity-type="showProjectsDialog ? 'project' : 'person'" |
||||
|
:recipient-entity-type="'person'" |
||||
|
/> |
||||
|
|
||||
|
<!-- ProjectViewView --> |
||||
|
<GiftedDialog |
||||
|
ref="giveDialogToThis" |
||||
|
:giver-entity-type="'person'" |
||||
|
:recipient-entity-type="'project'" |
||||
|
:to-project-id="projectId" |
||||
|
:is-from-project-view="true" |
||||
|
/> |
||||
|
|
||||
|
<!-- ClaimView --> |
||||
|
<GiftedDialog |
||||
|
ref="customGiveDialog" |
||||
|
:giver-entity-type="'person'" |
||||
|
:recipient-entity-type="projectInfo ? 'project' : 'person'" |
||||
|
:to-project-id="..." |
||||
|
/> |
||||
|
``` |
||||
|
|
||||
|
## Benefits |
||||
|
|
||||
|
### 1. **Declarative** |
||||
|
- Entity types are explicitly declared in the template |
||||
|
- No hidden logic in watchers or complex methods |
||||
|
- Clear intent at the call site |
||||
|
|
||||
|
### 2. **Reusable** |
||||
|
- Views can easily specify any combination of entity types |
||||
|
- No need to understand internal logic |
||||
|
- Simple inline logic is easy to understand |
||||
|
|
||||
|
### 3. **Maintainable** |
||||
|
- Adding new entity type combinations is straightforward |
||||
|
- Logic is visible directly in the template |
||||
|
- No additional files to maintain |
||||
|
|
||||
|
### 4. **Testable** |
||||
|
- Entity type logic is visible and predictable |
||||
|
- No complex state management to test |
||||
|
- Template logic can be easily verified |
||||
|
|
||||
|
### 5. **Type Safe** |
||||
|
- TypeScript ensures correct entity type values |
||||
|
- Compile-time validation of entity type combinations |
||||
|
|
||||
|
## Migration Guide |
||||
|
|
||||
|
### For Views Using GiftedDialog |
||||
|
|
||||
|
Simply update the template to use explicit entity type props: |
||||
|
|
||||
|
```vue |
||||
|
<!-- Before --> |
||||
|
<GiftedDialog :show-projects="showProjects" /> |
||||
|
|
||||
|
<!-- After --> |
||||
|
<GiftedDialog |
||||
|
:giver-entity-type="showProjects ? 'project' : 'person'" |
||||
|
:recipient-entity-type="'person'" |
||||
|
/> |
||||
|
``` |
||||
|
|
||||
|
### Common Patterns |
||||
|
|
||||
|
1. **Person-to-Person**: `giver-entity-type="'person'" recipient-entity-type="'person'"` |
||||
|
2. **Project-to-Person**: `giver-entity-type="'project'" recipient-entity-type="'person'"` |
||||
|
3. **Person-to-Project**: `giver-entity-type="'person'" recipient-entity-type="'project'"` |
||||
|
4. **Conditional Project**: `recipient-entity-type="hasProject ? 'project' : 'person'"` |
||||
|
|
||||
|
## Files Changed |
||||
|
|
||||
|
### Core Changes |
||||
|
- `src/components/GiftedDialog.vue` - Removed `updateEntityTypes()` method, added explicit props |
||||
|
|
||||
|
### View Updates |
||||
|
- `src/views/HomeView.vue` - Updated to use inline logic |
||||
|
- `src/views/ProjectViewView.vue` - Updated to use inline logic |
||||
|
- `src/views/ClaimView.vue` - Updated to use inline logic |
||||
|
- `src/views/ContactGiftingView.vue` - Updated to use inline logic |
||||
|
- `src/views/ContactsView.vue` - Updated to use inline logic |
||||
|
|
||||
|
## Backward Compatibility |
||||
|
|
||||
|
The refactoring maintains backward compatibility by: |
||||
|
- Keeping all existing props that are still needed (`fromProjectId`, `toProjectId`, `isFromProjectView`) |
||||
|
- Preserving the same component API for the `open()` method |
||||
|
- Maintaining the same template structure |
||||
|
|
||||
|
## Future Enhancements |
||||
|
|
||||
|
1. **Validation**: Add runtime validation for entity type combinations |
||||
|
2. **Documentation**: Add JSDoc comments to the component props |
||||
|
3. **Testing**: Add unit tests for the component with different entity type combinations |
||||
|
|
||||
|
## Conclusion |
||||
|
|
||||
|
This refactoring transforms `GiftedDialog` from a component with complex internal logic to a declarative, reusable component. The explicit entity type props make the component's behavior clear and predictable, while the simple inline logic keeps the code straightforward and maintainable. |
||||
|
|
||||
|
## Bug Fixes |
||||
|
|
||||
|
### Issue 1: Entity Type Preservation in Navigation |
||||
|
|
||||
|
**Problem**: When navigating from HomeView with `showProjects = true` to ContactGiftingView via "Show All", the entity type information was lost because `showAllQueryParams` returned an empty object for project contexts. |
||||
|
|
||||
|
**Solution**: Modified `EntitySelectionStep.vue` to always pass entity type information in the query parameters, even for project contexts. |
||||
|
|
||||
|
### Issue 2: Recipient Reset in ContactGiftingView |
||||
|
|
||||
|
**Problem**: When selecting a giver in ContactGiftingView, the recipient was always reset to "You" instead of preserving the current recipient. |
||||
|
|
||||
|
**Solution**: Updated ContactGiftingView to preserve the existing recipient from the context when selecting a giver, and enhanced the query parameter passing to include both giver and recipient information for better context preservation. |
||||
|
|
||||
|
### Issue 3: HomeView Project Button Entity Type Mismatch |
||||
|
|
||||
|
**Problem**: When navigating from HomeView Project button → change recipient → Show All → ContactGifting, the giver entity type was incorrectly set to "person" instead of "project". |
||||
|
|
||||
|
**Root Cause**: ContactGiftingView was inferring entity types from `fromProjectId` and `toProjectId` instead of using the explicitly passed `giverEntityType` and `recipientEntityType` from the query parameters. |
||||
|
|
||||
|
**Solution**: Updated ContactGiftingView to use the explicitly passed entity types from query parameters instead of inferring them from project IDs. |
||||
|
|
||||
|
### Files Modified for Bug Fixes |
||||
|
|
||||
|
- `src/components/EntitySelectionStep.vue` - Enhanced query parameter passing |
||||
|
- `src/views/ContactGiftingView.vue` - Improved context preservation logic and entity type handling |
Loading…
Reference in new issue