forked from jsnbuchanan/crowd-funder-for-time-pwa
Add notification utility helpers and update PlatformServiceMixin
Created notification utility approaches to consolidate verbose $notify calls: - Simple function utility (src/utils/notify.ts) - recommended approach - Vue 3 composable (src/composables/useNotifications.ts) - Utility class with mixin (src/utils/notificationUtils.ts) Updated ClaimView.vue to demonstrate usage, reducing notification code by ~70%. Enhanced PlatformServiceMixin with improved caching and database methods. Updated ShareMyContactInfoView.vue with mixin improvements. Provides consistent timeouts, standardized patterns, and type safety. Ready for migration alongside mixin updates.
This commit is contained in:
@@ -545,8 +545,8 @@ export const PlatformServiceMixin = {
|
||||
|
||||
/**
|
||||
* Load all contacts with caching - $contacts()
|
||||
* Ultra-concise shortcut with 60s TTL for performance
|
||||
* @returns Cached mapped array of all contacts
|
||||
* Contacts are cached for 60 seconds for performance
|
||||
* @returns Promise<Contact[]> Array of contact objects
|
||||
*/
|
||||
async $contacts(): Promise<Contact[]> {
|
||||
const cacheKey = "contacts_all";
|
||||
@@ -565,6 +565,16 @@ export const PlatformServiceMixin = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get total contact count - $contactCount()
|
||||
* Ultra-concise shortcut for getting number of contacts
|
||||
* @returns Promise<number> Total number of contacts
|
||||
*/
|
||||
async $contactCount(): Promise<number> {
|
||||
const countRow = await this.$one("SELECT COUNT(*) FROM contacts");
|
||||
return (countRow?.[0] as number) || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load settings with optional defaults WITHOUT caching - $settings()
|
||||
* Settings are loaded fresh every time for immediate consistency
|
||||
@@ -1136,6 +1146,7 @@ export interface IPlatformServiceMixin {
|
||||
$insertContact(contact: Partial<Contact>): Promise<boolean>;
|
||||
$updateContact(did: string, changes: Partial<Contact>): Promise<boolean>;
|
||||
$getAllContacts(): Promise<Contact[]>;
|
||||
$contactCount(): Promise<number>;
|
||||
$insertEntity(
|
||||
tableName: string,
|
||||
entity: Record<string, unknown>,
|
||||
@@ -1211,6 +1222,7 @@ declare module "@vue/runtime-core" {
|
||||
|
||||
// Specialized shortcuts - contacts cached, settings fresh
|
||||
$contacts(): Promise<Contact[]>;
|
||||
$contactCount(): Promise<number>;
|
||||
$settings(defaults?: Settings): Promise<Settings>;
|
||||
$accountSettings(did?: string, defaults?: Settings): Promise<Settings>;
|
||||
|
||||
|
||||
223
src/utils/notificationUtils.ts
Normal file
223
src/utils/notificationUtils.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
import { NotificationIface } from "../constants/app";
|
||||
|
||||
/**
|
||||
* Notification utility methods to reduce code duplication
|
||||
* and provide consistent notification patterns across the app
|
||||
*/
|
||||
|
||||
export interface NotificationHelper {
|
||||
notify: (notification: NotificationIface, timeout?: number) => void;
|
||||
success: (text: string, timeout?: number) => void;
|
||||
error: (text: string, timeout?: number) => void;
|
||||
warning: (text: string, timeout?: number) => void;
|
||||
info: (text: string, timeout?: number) => void;
|
||||
toast: (title: string, text?: string, timeout?: number) => void;
|
||||
copied: (item: string, timeout?: number) => void;
|
||||
sent: (timeout?: number) => void;
|
||||
confirm: (text: string, onYes: () => Promise<void>, timeout?: number) => void;
|
||||
confirmationSubmitted: (timeout?: number) => void;
|
||||
alreadyConfirmed: (timeout?: number) => void;
|
||||
cannotConfirmIssuer: (timeout?: number) => void;
|
||||
cannotConfirmHidden: (timeout?: number) => void;
|
||||
notRegistered: (timeout?: number) => void;
|
||||
notAGive: (timeout?: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard notification timeouts
|
||||
*/
|
||||
export const NOTIFICATION_TIMEOUTS = {
|
||||
BRIEF: 1000, // Very brief toasts ("Sent..." messages)
|
||||
SHORT: 2000, // Short notifications (clipboard copies, quick confirmations)
|
||||
STANDARD: 3000, // Standard notifications (success messages, general info)
|
||||
LONG: 5000, // Longer notifications (errors, warnings, important info)
|
||||
VERY_LONG: 7000, // Very long notifications (complex operations)
|
||||
MODAL: -1, // Modal confirmations (no auto-dismiss)
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Standard notification titles
|
||||
*/
|
||||
export const NOTIFICATION_TITLES = {
|
||||
SUCCESS: "Success",
|
||||
ERROR: "Error",
|
||||
WARNING: "Warning",
|
||||
INFO: "Info",
|
||||
COPIED: "Copied",
|
||||
SENT: "Sent...",
|
||||
CONFIRM: "Confirm",
|
||||
NOT_REGISTERED: "Not Registered",
|
||||
ALREADY_CONFIRMED: "Already Confirmed",
|
||||
CANNOT_CONFIRM: "Cannot Confirm",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Standard notification messages
|
||||
*/
|
||||
export const NOTIFICATION_MESSAGES = {
|
||||
GENERIC_ERROR: "Something went wrong.",
|
||||
GENERIC_SUCCESS: "Operation completed successfully.",
|
||||
CLIPBOARD_COPIED: (item: string) => `${item} was copied to the clipboard.`,
|
||||
SENT_BRIEF: "Sent...",
|
||||
CONFIRMATION_SUBMITTED: "Confirmation submitted.",
|
||||
ALREADY_CONFIRMED: "You already confirmed this claim.",
|
||||
CANNOT_CONFIRM_ISSUER: "You cannot confirm this because you issued this claim.",
|
||||
CANNOT_CONFIRM_HIDDEN: "You cannot confirm this because some people are hidden.",
|
||||
NOT_REGISTERED: "Someone needs to register you before you can confirm.",
|
||||
NOT_A_GIVE: "This is not a giving action to confirm.",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Creates a notification helper with utility methods
|
||||
*/
|
||||
export function createNotificationHelper(notifyFn: (notification: NotificationIface, timeout?: number) => void): NotificationHelper {
|
||||
return {
|
||||
notify: notifyFn,
|
||||
|
||||
// Success notifications
|
||||
success: (text: string, timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: NOTIFICATION_TITLES.SUCCESS,
|
||||
text,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Error notifications
|
||||
error: (text: string, timeout = NOTIFICATION_TIMEOUTS.LONG) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: NOTIFICATION_TITLES.ERROR,
|
||||
text,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Warning notifications
|
||||
warning: (text: string, timeout = NOTIFICATION_TIMEOUTS.LONG) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: NOTIFICATION_TITLES.WARNING,
|
||||
text,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Info notifications
|
||||
info: (text: string, timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.INFO,
|
||||
text,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Toast notifications (brief)
|
||||
toast: (title: string, text?: string, timeout = NOTIFICATION_TIMEOUTS.BRIEF) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "toast",
|
||||
title,
|
||||
text,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Clipboard copy notifications
|
||||
copied: (item: string, timeout = NOTIFICATION_TIMEOUTS.SHORT) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "toast",
|
||||
title: NOTIFICATION_TITLES.COPIED,
|
||||
text: NOTIFICATION_MESSAGES.CLIPBOARD_COPIED(item),
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Sent brief notification
|
||||
sent: (timeout = NOTIFICATION_TIMEOUTS.BRIEF) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "toast",
|
||||
title: NOTIFICATION_TITLES.SENT,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Confirmation modal
|
||||
confirm: (text: string, onYes: () => Promise<void>, timeout = NOTIFICATION_TIMEOUTS.MODAL) => {
|
||||
notifyFn({
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: NOTIFICATION_TITLES.CONFIRM,
|
||||
text,
|
||||
onYes,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
// Standard confirmation messages
|
||||
confirmationSubmitted: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: NOTIFICATION_TITLES.SUCCESS,
|
||||
text: NOTIFICATION_MESSAGES.CONFIRMATION_SUBMITTED,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
alreadyConfirmed: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.ALREADY_CONFIRMED,
|
||||
text: NOTIFICATION_MESSAGES.ALREADY_CONFIRMED,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
cannotConfirmIssuer: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.CANNOT_CONFIRM,
|
||||
text: NOTIFICATION_MESSAGES.CANNOT_CONFIRM_ISSUER,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
cannotConfirmHidden: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.CANNOT_CONFIRM,
|
||||
text: NOTIFICATION_MESSAGES.CANNOT_CONFIRM_HIDDEN,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
notRegistered: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.NOT_REGISTERED,
|
||||
text: NOTIFICATION_MESSAGES.NOT_REGISTERED,
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
notAGive: (timeout = NOTIFICATION_TIMEOUTS.STANDARD) => {
|
||||
notifyFn({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: NOTIFICATION_TITLES.INFO,
|
||||
text: NOTIFICATION_MESSAGES.NOT_A_GIVE,
|
||||
}, timeout);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue mixin to add notification helpers to components
|
||||
*/
|
||||
export const NotificationMixin = {
|
||||
computed: {
|
||||
$notifyHelper() {
|
||||
return createNotificationHelper((this as any).$notify);
|
||||
},
|
||||
},
|
||||
};
|
||||
136
src/utils/notify.ts
Normal file
136
src/utils/notify.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { NotificationIface } from '../constants/app';
|
||||
|
||||
/**
|
||||
* Simple notification utility functions
|
||||
* Provides the most concise API for common notification patterns
|
||||
*/
|
||||
|
||||
export type NotifyFunction = (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
// Standard timeouts
|
||||
export const TIMEOUTS = {
|
||||
BRIEF: 1000, // Very brief toasts ("Sent..." messages)
|
||||
SHORT: 2000, // Short notifications (clipboard copies, quick confirmations)
|
||||
STANDARD: 3000, // Standard notifications (success messages, general info)
|
||||
LONG: 5000, // Longer notifications (errors, warnings, important info)
|
||||
VERY_LONG: 7000, // Very long notifications (complex operations)
|
||||
MODAL: -1, // Modal confirmations (no auto-dismiss)
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Create notification helpers for a given notify function
|
||||
*/
|
||||
export function createNotifyHelpers(notify: NotifyFunction) {
|
||||
return {
|
||||
// Success notifications
|
||||
success: (text: string, timeout?: number) =>
|
||||
notify({ group: "alert", type: "success", title: "Success", text }, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
// Error notifications
|
||||
error: (text: string, timeout?: number) =>
|
||||
notify({ group: "alert", type: "danger", title: "Error", text }, timeout || TIMEOUTS.LONG),
|
||||
|
||||
// Warning notifications
|
||||
warning: (text: string, timeout?: number) =>
|
||||
notify({ group: "alert", type: "warning", title: "Warning", text }, timeout || TIMEOUTS.LONG),
|
||||
|
||||
// Info notifications
|
||||
info: (text: string, timeout?: number) =>
|
||||
notify({ group: "alert", type: "info", title: "Info", text }, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
// Toast notifications (brief)
|
||||
toast: (title: string, text?: string, timeout?: number) =>
|
||||
notify({ group: "alert", type: "toast", title, text }, timeout || TIMEOUTS.BRIEF),
|
||||
|
||||
// Clipboard copy notifications
|
||||
copied: (item: string, timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "toast",
|
||||
title: "Copied",
|
||||
text: `${item} was copied to the clipboard.`
|
||||
}, timeout || TIMEOUTS.SHORT),
|
||||
|
||||
// Sent brief notification
|
||||
sent: (timeout?: number) =>
|
||||
notify({ group: "alert", type: "toast", title: "Sent..." }, timeout || TIMEOUTS.BRIEF),
|
||||
|
||||
// Confirmation modal
|
||||
confirm: (text: string, onYes: () => Promise<void>, timeout?: number) =>
|
||||
notify({
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: "Confirm",
|
||||
text,
|
||||
onYes
|
||||
}, timeout || TIMEOUTS.MODAL),
|
||||
|
||||
// Standard confirmation messages
|
||||
confirmationSubmitted: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Success",
|
||||
text: "Confirmation submitted."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
// Common error patterns
|
||||
genericError: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Something went wrong."
|
||||
}, timeout || TIMEOUTS.LONG),
|
||||
|
||||
// Common success patterns
|
||||
genericSuccess: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Success",
|
||||
text: "Operation completed successfully."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
// Common confirmation patterns
|
||||
alreadyConfirmed: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Already Confirmed",
|
||||
text: "You already confirmed this claim."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
cannotConfirmIssuer: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Cannot Confirm",
|
||||
text: "You cannot confirm this because you issued this claim."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
cannotConfirmHidden: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Cannot Confirm",
|
||||
text: "You cannot confirm this because some people are hidden."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
notRegistered: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Not Registered",
|
||||
text: "Someone needs to register you before you can confirm."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
|
||||
notAGive: (timeout?: number) =>
|
||||
notify({
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Info",
|
||||
text: "This is not a giving action to confirm."
|
||||
}, timeout || TIMEOUTS.STANDARD),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user