Feature: notify on click why entity is disabled
This commit is contained in:
@@ -14,6 +14,8 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
:selectable="youSelectable"
|
:selectable="youSelectable"
|
||||||
:conflicted="youConflicted"
|
:conflicted="youConflicted"
|
||||||
:entity-data="youEntityData"
|
:entity-data="youEntityData"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
@entity-selected="handleEntitySelected"
|
@entity-selected="handleEntitySelected"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -23,6 +25,8 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
label="Unnamed"
|
label="Unnamed"
|
||||||
icon="circle-question"
|
icon="circle-question"
|
||||||
:entity-data="unnamedEntityData"
|
:entity-data="unnamedEntityData"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
@entity-selected="handleEntitySelected"
|
@entity-selected="handleEntitySelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -38,23 +42,27 @@ projects, and special entities with selection. * * @author Matthew Raymer */
|
|||||||
<!-- Entity cards (people or projects) -->
|
<!-- Entity cards (people or projects) -->
|
||||||
<template v-if="entityType === 'people'">
|
<template v-if="entityType === 'people'">
|
||||||
<PersonCard
|
<PersonCard
|
||||||
v-for="person in displayedEntities"
|
v-for="person in displayedEntities as Contact[]"
|
||||||
:key="person.did"
|
:key="person.did"
|
||||||
:person="person"
|
:person="person"
|
||||||
:conflicted="isPersonConflicted(person.did)"
|
:conflicted="isPersonConflicted(person.did)"
|
||||||
:show-time-icon="true"
|
:show-time-icon="true"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
@person-selected="handlePersonSelected"
|
@person-selected="handlePersonSelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="entityType === 'projects'">
|
<template v-else-if="entityType === 'projects'">
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
v-for="project in displayedEntities"
|
v-for="project in displayedEntities as PlanData[]"
|
||||||
:key="project.handleId"
|
:key="project.handleId"
|
||||||
:project="project"
|
:project="project"
|
||||||
:active-did="activeDid"
|
:active-did="activeDid"
|
||||||
:all-my-dids="allMyDids"
|
:all-my-dids="allMyDids"
|
||||||
:all-contacts="allContacts"
|
:all-contacts="allContacts"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
@project-selected="handleProjectSelected"
|
@project-selected="handleProjectSelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -77,6 +85,7 @@ import SpecialEntityCard from "./SpecialEntityCard.vue";
|
|||||||
import ShowAllCard from "./ShowAllCard.vue";
|
import ShowAllCard from "./ShowAllCard.vue";
|
||||||
import { Contact } from "../db/tables/contacts";
|
import { Contact } from "../db/tables/contacts";
|
||||||
import { PlanData } from "../interfaces/records";
|
import { PlanData } from "../interfaces/records";
|
||||||
|
import { NotificationIface } from "../constants/app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntityGrid - Unified grid layout for displaying people or projects
|
* EntityGrid - Unified grid layout for displaying people or projects
|
||||||
@@ -88,6 +97,7 @@ import { PlanData } from "../interfaces/records";
|
|||||||
* - Empty state messaging
|
* - Empty state messaging
|
||||||
* - Show All navigation
|
* - Show All navigation
|
||||||
* - Event delegation for entity selection
|
* - Event delegation for entity selection
|
||||||
|
* - Warning notifications for conflicted entities
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -142,6 +152,14 @@ export default class EntityGrid extends Vue {
|
|||||||
@Prop({ default: () => ({}) })
|
@Prop({ default: () => ({}) })
|
||||||
showAllQueryParams!: Record<string, string>;
|
showAllQueryParams!: Record<string, string>;
|
||||||
|
|
||||||
|
/** Notification function from parent component */
|
||||||
|
@Prop()
|
||||||
|
notify?: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
|
/** Context for conflict messages (e.g., "giver", "recipient") */
|
||||||
|
@Prop({ default: "other party" })
|
||||||
|
conflictContext!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed CSS classes for the grid layout
|
* Computed CSS classes for the grid layout
|
||||||
*/
|
*/
|
||||||
@@ -241,7 +259,7 @@ export default class EntityGrid extends Vue {
|
|||||||
handleEntitySelected(event: {
|
handleEntitySelected(event: {
|
||||||
type: string;
|
type: string;
|
||||||
entityType: string;
|
entityType: string;
|
||||||
data: any;
|
data: { did?: string; name: string };
|
||||||
}): void {
|
}): void {
|
||||||
this.emitEntitySelected({
|
this.emitEntitySelected({
|
||||||
type: "special",
|
type: "special",
|
||||||
@@ -253,7 +271,15 @@ export default class EntityGrid extends Vue {
|
|||||||
// Emit methods using @Emit decorator
|
// Emit methods using @Emit decorator
|
||||||
|
|
||||||
@Emit("entity-selected")
|
@Emit("entity-selected")
|
||||||
emitEntitySelected(data: any): any {
|
emitEntitySelected(data: {
|
||||||
|
type: "person" | "project" | "special";
|
||||||
|
entityType?: string;
|
||||||
|
data: Contact | PlanData | { did?: string; name: string };
|
||||||
|
}): {
|
||||||
|
type: "person" | "project" | "special";
|
||||||
|
entityType?: string;
|
||||||
|
data: Contact | PlanData | { did?: string; name: string };
|
||||||
|
} {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ with dynamic labeling and grid display. * * @author Matthew Raymer */
|
|||||||
:you-selectable="youSelectable"
|
:you-selectable="youSelectable"
|
||||||
:show-all-route="showAllRoute"
|
:show-all-route="showAllRoute"
|
||||||
:show-all-query-params="showAllQueryParams"
|
:show-all-query-params="showAllQueryParams"
|
||||||
|
:notify="notify"
|
||||||
|
:conflict-context="conflictContext"
|
||||||
@entity-selected="handleEntitySelected"
|
@entity-selected="handleEntitySelected"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -36,6 +38,7 @@ import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
|
|||||||
import EntityGrid from "./EntityGrid.vue";
|
import EntityGrid from "./EntityGrid.vue";
|
||||||
import { Contact } from "../db/tables/contacts";
|
import { Contact } from "../db/tables/contacts";
|
||||||
import { PlanData } from "../interfaces/records";
|
import { PlanData } from "../interfaces/records";
|
||||||
|
import { NotificationIface } from "../constants/app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity data interface for giver/receiver
|
* Entity data interface for giver/receiver
|
||||||
@@ -67,6 +70,7 @@ interface EntitySelectionEvent {
|
|||||||
* - Show All navigation with context preservation
|
* - Show All navigation with context preservation
|
||||||
* - Cancel functionality
|
* - Cancel functionality
|
||||||
* - Event delegation for entity selection
|
* - Event delegation for entity selection
|
||||||
|
* - Warning notifications for conflicted entities
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -130,6 +134,10 @@ export default class EntitySelectionStep extends Vue {
|
|||||||
@Prop()
|
@Prop()
|
||||||
receiver?: EntityData | null;
|
receiver?: EntityData | null;
|
||||||
|
|
||||||
|
/** Notification function from parent component */
|
||||||
|
@Prop()
|
||||||
|
notify?: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed step label based on context
|
* Computed step label based on context
|
||||||
*/
|
*/
|
||||||
@@ -143,6 +151,17 @@ export default class EntitySelectionStep extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computed conflict context for better error messages
|
||||||
|
*/
|
||||||
|
get conflictContext(): string {
|
||||||
|
if (this.stepType === "giver") {
|
||||||
|
return "recipient";
|
||||||
|
} else {
|
||||||
|
return "giver";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to show projects in the grid
|
* Whether to show projects in the grid
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
:to-project-id="toProjectId"
|
:to-project-id="toProjectId"
|
||||||
:giver="giver"
|
:giver="giver"
|
||||||
:receiver="receiver"
|
:receiver="receiver"
|
||||||
|
:notify="$notify"
|
||||||
@entity-selected="handleEntitySelected"
|
@entity-selected="handleEntitySelected"
|
||||||
@cancel="cancel"
|
@cancel="cancel"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ conflict detection. * * @author Matthew Raymer */
|
|||||||
import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
|
import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
|
||||||
import EntityIcon from "./EntityIcon.vue";
|
import EntityIcon from "./EntityIcon.vue";
|
||||||
import { Contact } from "../db/tables/contacts";
|
import { Contact } from "../db/tables/contacts";
|
||||||
|
import { NotificationIface } from "../constants/app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PersonCard - Individual person display with selection capability
|
* PersonCard - Individual person display with selection capability
|
||||||
@@ -44,6 +45,7 @@ import { Contact } from "../db/tables/contacts";
|
|||||||
* - Time icon overlay for contacts
|
* - Time icon overlay for contacts
|
||||||
* - Click event handling
|
* - Click event handling
|
||||||
* - Emits click events for parent handling
|
* - Emits click events for parent handling
|
||||||
|
* - Warning notifications for conflicted entities
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -67,6 +69,14 @@ export default class PersonCard extends Vue {
|
|||||||
@Prop({ default: false })
|
@Prop({ default: false })
|
||||||
showTimeIcon!: boolean;
|
showTimeIcon!: boolean;
|
||||||
|
|
||||||
|
/** Notification function from parent component */
|
||||||
|
@Prop()
|
||||||
|
notify?: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
|
/** Context for conflict messages (e.g., "giver", "recipient") */
|
||||||
|
@Prop({ default: "other party" })
|
||||||
|
conflictContext!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed CSS classes for the card
|
* Computed CSS classes for the card
|
||||||
*/
|
*/
|
||||||
@@ -92,11 +102,22 @@ export default class PersonCard extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle card click - only emit if selectable and not conflicted
|
* Handle card click - emit if selectable and not conflicted, show warning if conflicted
|
||||||
*/
|
*/
|
||||||
handleClick(): void {
|
handleClick(): void {
|
||||||
if (this.selectable && !this.conflicted) {
|
if (this.selectable && !this.conflicted) {
|
||||||
this.emitPersonSelected(this.person);
|
this.emitPersonSelected(this.person);
|
||||||
|
} else if (this.conflicted && this.notify) {
|
||||||
|
// Show warning notification for conflicted entity
|
||||||
|
this.notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Cannot Select",
|
||||||
|
text: `You cannot select "${this.person.name || this.person.did || "Unnamed"}" because they are already selected as the ${this.conflictContext}.`,
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ conflict detection and selection capability. * * @author Matthew Raymer */
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Prop, Vue } from "vue-facing-decorator";
|
import { Component, Prop, Vue } from "vue-facing-decorator";
|
||||||
import { Emit } from "vue-facing-decorator";
|
import { Emit } from "vue-facing-decorator";
|
||||||
|
import { NotificationIface } from "../constants/app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SpecialEntityCard - Displays special entities with selection capability
|
* SpecialEntityCard - Displays special entities with selection capability
|
||||||
@@ -23,6 +24,7 @@ import { Emit } from "vue-facing-decorator";
|
|||||||
* - Handles conflict states and selection
|
* - Handles conflict states and selection
|
||||||
* - Emits selection events with entity data
|
* - Emits selection events with entity data
|
||||||
* - Configurable styling based on entity type
|
* - Configurable styling based on entity type
|
||||||
|
* - Warning notifications for conflicted entities
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
emits: ["entity-selected"],
|
emits: ["entity-selected"],
|
||||||
@@ -52,6 +54,14 @@ export default class SpecialEntityCard extends Vue {
|
|||||||
@Prop({ required: true })
|
@Prop({ required: true })
|
||||||
entityData!: { did?: string; name: string };
|
entityData!: { did?: string; name: string };
|
||||||
|
|
||||||
|
/** Notification function from parent component */
|
||||||
|
@Prop()
|
||||||
|
notify?: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
|
/** Context for conflict messages (e.g., "giver", "recipient") */
|
||||||
|
@Prop({ default: "other party" })
|
||||||
|
conflictContext!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed CSS classes for the card container
|
* Computed CSS classes for the card container
|
||||||
*/
|
*/
|
||||||
@@ -109,7 +119,7 @@ export default class SpecialEntityCard extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle card click - only emit if selectable and not conflicted
|
* Handle card click - emit if selectable and not conflicted, show warning if conflicted
|
||||||
*/
|
*/
|
||||||
handleClick(): void {
|
handleClick(): void {
|
||||||
if (this.selectable && !this.conflicted) {
|
if (this.selectable && !this.conflicted) {
|
||||||
@@ -118,13 +128,32 @@ export default class SpecialEntityCard extends Vue {
|
|||||||
entityType: this.entityType,
|
entityType: this.entityType,
|
||||||
data: this.entityData,
|
data: this.entityData,
|
||||||
});
|
});
|
||||||
|
} else if (this.conflicted && this.notify) {
|
||||||
|
// Show warning notification for conflicted entity
|
||||||
|
this.notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Cannot Select",
|
||||||
|
text: `You cannot select "${this.label}" because you are already selected as the ${this.conflictContext}.`,
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit methods using @Emit decorator
|
// Emit methods using @Emit decorator
|
||||||
|
|
||||||
@Emit("entity-selected")
|
@Emit("entity-selected")
|
||||||
emitEntitySelected(data: any): any {
|
emitEntitySelected(data: {
|
||||||
|
type: string;
|
||||||
|
entityType: string;
|
||||||
|
data: { did?: string; name: string };
|
||||||
|
}): {
|
||||||
|
type: string;
|
||||||
|
entityType: string;
|
||||||
|
data: { did?: string; name: string };
|
||||||
|
} {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user