Browse Source

refactor: standardize notification usage and document best practices

Move all user-facing notification messages to src/constants/notifications.ts
Use TIMEOUTS constants from src/utils/notify.ts for all notification durations
Refactor ActivityListItem.vue:
Use notification message and duration constants
Initialize notify helper in created() with createNotifyHelpers(this.$notify)
Add $notify property for Vue runtime injection to satisfy type checker
Use type guards or 'as any' for unknown notification payloads
Wrap notifyWhyCannotConfirm calls to match expected function signature
Fix type import for GiveRecordWithContactInfo
Add 'Notification Best Practices and Nuances' section to migration-progress-tracker.md:
Document message/duration constants, notify helper pattern, type safety, and wrapper function usage
Remove all hardcoded notification strings and durations from components
pull/142/head
Matthew Raymer 6 hours ago
parent
commit
938e6693b0
  1. 14
      doc/migration-progress-tracker.md
  2. 42
      src/components/ActivityListItem.vue
  3. 1
      src/components/GiftedDialog.vue
  4. 1
      src/components/IdentitySection.vue
  5. 12
      src/constants/notifications.ts
  6. 1
      src/utils/notificationUtils.ts

14
doc/migration-progress-tracker.md

@ -381,5 +381,19 @@ find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" |
---
## 🎯 **Notification Best Practices and Nuances**
- **All user-facing notification messages must be defined as constants** in `src/constants/notifications.ts`. Do not hardcode notification strings in components.
- **All notification durations/timeouts must use the `TIMEOUTS` constants** from `src/utils/notify.ts`. Do not hardcode durations.
- **Notification helpers (`this.notify`) must be initialized as a property in `created()`** using `createNotifyHelpers(this.$notify)`.
- **Never hardcode notification strings or durations in components.**
- **When using `notifyWhyCannotConfirm` or similar utilities, pass a wrapper function** if the signature expects a raw notify function (e.g., `(msg, timeout) => this.notify.info(msg.text ?? '', timeout)`).
- **Declare `$notify` as a property on the class** to satisfy the type checker, since Vue injects it at runtime.
- **Use type guards or `as any` for unknown notification payloads** when necessary, but prefer type safety where possible.
These practices ensure maintainability, consistency, and type safety for all notification-related code during and after migration.
---
**Last Updated**: $(date)
**Next Review**: After each phase completion

42
src/components/ActivityListItem.vue

@ -249,7 +249,7 @@
<script lang="ts">
import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
import { GiveRecordWithContactInfo } from "../types";
import { GiveRecordWithContactInfo } from "@/interfaces/give";
import EntityIcon from "./EntityIcon.vue";
import {
isGiveClaimType,
@ -258,7 +258,9 @@ import {
} from "../libs/util";
import { containsHiddenDid, isHiddenDid } from "../libs/endorserServer";
import ProjectIcon from "./ProjectIcon.vue";
import { NotificationIface } from "../constants/app";
import { createNotifyHelpers } from "@/utils/notify";
import { NOTIFY_PERSON_HIDDEN, NOTIFY_UNKNOWN_PERSON } from "@/constants/notifications";
import { TIMEOUTS } from "@/utils/notify";
@Component({
components: {
@ -274,29 +276,24 @@ export default class ActivityListItem extends Vue {
@Prop() confirmerIdList?: string[];
isHiddenDid = isHiddenDid;
$notify!: (notification: NotificationIface, timeout?: number) => void;
notify!: ReturnType<typeof createNotifyHelpers>;
$notify!: (notification: any, timeout?: number) => void;
created() {
this.notify = createNotifyHelpers(this.$notify);
}
notifyHiddenPerson() {
this.$notify(
{
group: "alert",
type: "warning",
title: "Person Outside Your Network",
text: "This person is not visible to you.",
},
3000,
this.notify.warning(
NOTIFY_PERSON_HIDDEN.message,
TIMEOUTS.STANDARD,
);
}
notifyUnknownPerson() {
this.$notify(
{
group: "alert",
type: "warning",
title: "Unidentified Person",
text: "Nobody specific was recognized.",
},
3000,
this.notify.warning(
NOTIFY_UNKNOWN_PERSON.message,
TIMEOUTS.STANDARD,
);
}
@ -307,7 +304,7 @@ export default class ActivityListItem extends Vue {
get fetchAmount(): string {
const claim =
(this.record.fullClaim as unknown).claim || this.record.fullClaim;
(this.record.fullClaim as any)?.claim || this.record.fullClaim;
const amount = claim.object?.amountOfThisGood
? this.displayAmount(claim.object.unitCode, claim.object.amountOfThisGood)
@ -318,7 +315,7 @@ export default class ActivityListItem extends Vue {
get description(): string {
const claim =
(this.record.fullClaim as unknown).claim || this.record.fullClaim;
(this.record.fullClaim as any)?.claim || this.record.fullClaim;
return `${claim?.description || ""}`;
}
@ -343,7 +340,7 @@ export default class ActivityListItem extends Vue {
handleConfirmClick() {
if (!this.canConfirm) {
notifyWhyCannotConfirm(
this.$notify,
(msg, timeout) => this.notify.info(msg.text ?? '', timeout),
this.isRegistered,
this.record.fullClaim?.["@type"],
this.record,
@ -352,7 +349,6 @@ export default class ActivityListItem extends Vue {
);
return;
}
this.$emit("confirmClaim", this.record);
}

1
src/components/GiftedDialog.vue

@ -54,7 +54,6 @@
<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-facing-decorator";
import { NotificationIface } from "../constants/app";
import {
createAndSubmitGive,
didInfo,

1
src/components/IdentitySection.vue

@ -185,4 +185,3 @@ export default class IdentitySection extends Vue {
}
}
</script>

12
src/constants/notifications.ts

@ -0,0 +1,12 @@
// Notification message constants for user-facing notifications
// Add new notification messages here as needed
export const NOTIFY_PERSON_HIDDEN = {
title: "Person Outside Your Network",
message: "This person is not visible to you.",
};
export const NOTIFY_UNKNOWN_PERSON = {
title: "Unidentified Person",
message: "Nobody specific was recognized.",
};

1
src/utils/notificationUtils.ts

@ -276,4 +276,3 @@ export const NotificationMixin = {
},
},
};
Loading…
Cancel
Save