diff --git a/docs/refactoring/GiftedDialog-EntityTypes-Refactoring.md b/docs/refactoring/GiftedDialog-EntityTypes-Refactoring.md new file mode 100644 index 00000000..78162fd4 --- /dev/null +++ b/docs/refactoring/GiftedDialog-EntityTypes-Refactoring.md @@ -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 + + + + + + + + +``` + +## 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 + + + + + +``` + +### 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 \ No newline at end of file diff --git a/src/components/EntitySelectionStep.vue b/src/components/EntitySelectionStep.vue index 185fb929..ee144c75 100644 --- a/src/components/EntitySelectionStep.vue +++ b/src/components/EntitySelectionStep.vue @@ -234,11 +234,7 @@ export default class EntitySelectionStep extends Vue { * Query parameters for "Show All" navigation */ get showAllQueryParams(): Record { - if (this.shouldShowProjects) { - return {}; - } - - return { + const baseParams = { stepType: this.stepType, giverEntityType: this.giverEntityType, recipientEntityType: this.recipientEntityType, @@ -247,26 +243,31 @@ export default class EntitySelectionStep extends Vue { amountInput: this.amountInput, unitCode: this.unitCode, offerId: this.offerId, - ...(this.stepType === "giver" - ? { - recipientProjectId: this.toProjectId || "", - recipientProjectName: this.receiver?.name || "", - recipientProjectImage: this.receiver?.image || "", - recipientProjectHandleId: this.receiver?.handleId || "", - recipientDid: this.receiver?.did || "", - } - : { - giverProjectId: this.fromProjectId || "", - giverProjectName: this.giver?.name || "", - giverProjectImage: this.giver?.image || "", - giverProjectHandleId: this.giver?.handleId || "", - giverDid: this.giver?.did || "", - }), fromProjectId: this.fromProjectId, toProjectId: this.toProjectId, showProjects: this.showProjects.toString(), isFromProjectView: this.isFromProjectView.toString(), }; + + if (this.shouldShowProjects) { + // For project contexts, still pass entity type information + return baseParams; + } + + return { + ...baseParams, + // Always pass both giver and recipient info for context preservation + giverProjectId: this.fromProjectId || "", + giverProjectName: this.giver?.name || "", + giverProjectImage: this.giver?.image || "", + giverProjectHandleId: this.giver?.handleId || "", + giverDid: this.giver?.did || "", + recipientProjectId: this.toProjectId || "", + recipientProjectName: this.receiver?.name || "", + recipientProjectImage: this.receiver?.image || "", + recipientProjectHandleId: this.receiver?.handleId || "", + recipientDid: this.receiver?.did || "", + }; } /** diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index 41166c00..eebce841 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -3,7 +3,7 @@