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