Browse Source
- Replaced direct $notify calls with notification helper utilities for consistency and reduced duplication. - Updated AccountViewView.vue, PlatformServiceMixin.ts, and ShareMyContactInfoView.vue to use notification helpers. - Added explicit TypeScript types and constants for notification patterns. - Suppressed ESLint 'any' warning in notification mixin helper. - Ensured all affected files pass linting.pull/142/head
7 changed files with 1000 additions and 699 deletions
@ -0,0 +1,128 @@ |
|||
/** |
|||
* Constants for AccountViewView component |
|||
* Centralizes magic strings and provides type safety |
|||
*/ |
|||
|
|||
export const ACCOUNT_VIEW_CONSTANTS = { |
|||
// Error messages
|
|||
ERRORS: { |
|||
PROFILE_NOT_AVAILABLE: "Your server profile is not available.", |
|||
PROFILE_LOAD_ERROR: |
|||
"See the Help page about errors with your personal data.", |
|||
BROWSER_NOTIFICATIONS_UNSUPPORTED: |
|||
"This browser does not support notifications. Use Chrome, or install this to the home screen, or try other suggestions on the 'Troubleshoot your notifications' page.", |
|||
IMAGE_DELETE_PROBLEM: |
|||
"There was a problem deleting the image. Contact support if you want it removed from the servers.", |
|||
IMAGE_DELETE_ERROR: "There was an error deleting the image.", |
|||
SETTINGS_UPDATE_ERROR: |
|||
"Unable to update your settings. Check claim limits again.", |
|||
IMPORT_ERROR: "There was an error reading that Dexie file.", |
|||
EXPORT_ERROR: "There was an error exporting the data.", |
|||
PROFILE_SAVE_ERROR: "There was an error saving your profile.", |
|||
PROFILE_DELETE_ERROR: "There was an error deleting your profile.", |
|||
PROFILE_NOT_SAVED: "Profile not saved", |
|||
PROFILE_NOT_DELETED: "Profile not deleted", |
|||
UNABLE_TO_LOAD_PROFILE: "Unable to load profile.", |
|||
}, |
|||
|
|||
// Success messages
|
|||
SUCCESS: { |
|||
PROFILE_SAVED: "Your profile has been updated successfully.", |
|||
PROFILE_DELETED: "Your profile has been deleted successfully.", |
|||
IMPORT_COMPLETE: "Import Complete", |
|||
PROFILE_DELETED_SILENT: "Your profile has been deleted successfully.", |
|||
}, |
|||
|
|||
// Info messages
|
|||
INFO: { |
|||
PROFILE_INFO: |
|||
"This data will be published for all to see, so be careful what your write. Your ID will only be shared with people who you allow to see your activity.", |
|||
NO_PROFILE_LOCATION: "No profile location is saved.", |
|||
RELOAD_VAPID: |
|||
"Now reload the app to get a new VAPID to use with this push server.", |
|||
}, |
|||
|
|||
// Warning messages
|
|||
WARNINGS: { |
|||
IMAGE_DELETE_WARNING: |
|||
"Note that anyone with you already as a contact will no longer see a picture, and you will have to reshare your data with them if you save a new picture. Are you sure you want to delete your profile picture?", |
|||
ERASE_LOCATION_WARNING: |
|||
"Are you sure you don't want to mark a location? This will erase the current location.", |
|||
DELETE_PROFILE_WARNING: |
|||
"Are you sure you want to delete your public profile? This will remove your description and location from the server, and it cannot be undone.", |
|||
IMPORT_REPLACE_WARNING: |
|||
"This will replace all settings and contacts, so we recommend you first do the backup step above. Are you sure you want to import and replace all contacts and settings?", |
|||
}, |
|||
|
|||
// Notification messages
|
|||
NOTIFICATIONS: { |
|||
NEW_ACTIVITY_INFO: ` |
|||
This will only notify you when there is new relevant activity for you personally. |
|||
Note that it runs on your device and many factors may affect delivery, |
|||
so if you want a reliable but simple daily notification then choose a 'Reminder'. |
|||
Do you want more details? |
|||
`,
|
|||
REMINDER_INFO: ` |
|||
This will notify you at a specific time each day. |
|||
Note that it does not give you personalized notifications, |
|||
so if you want less reliable but personalized notification then choose a 'New Activity' Notification. |
|||
Do you want more details? |
|||
`,
|
|||
}, |
|||
|
|||
// UI text
|
|||
UI: { |
|||
COPIED: "Copied", |
|||
SENT: "Sent...", |
|||
RECORDING_GIVE: "Recording the give...", |
|||
RECORDING_OFFER: "Recording the offer...", |
|||
}, |
|||
|
|||
// Limits messages
|
|||
LIMITS: { |
|||
NO_IDENTIFIER: "You have no identifier, or your data has been corrupted.", |
|||
NO_LIMITS_FOUND: "No limits were found, so no actions are allowed.", |
|||
NO_IMAGE_ACCESS: "You don't have access to upload images.", |
|||
CANNOT_UPLOAD_IMAGES: "You cannot upload images.", |
|||
BAD_SERVER_RESPONSE: "Bad server response.", |
|||
ERROR_RETRIEVING_LIMITS: "Got an error retrieving limits.", |
|||
}, |
|||
|
|||
// Project assignment errors
|
|||
PROJECT_ERRORS: { |
|||
MISSING_PROJECT: |
|||
"To assign to a project, you must open this page through a project.", |
|||
CONFLICT_RECIPIENT: |
|||
"You cannot assign both to a project and to a recipient.", |
|||
MISSING_RECIPIENT: |
|||
"To assign to a recipient, you must open this page from a contact.", |
|||
CONFLICT_PROJECT: "You cannot assign both to a recipient and to a project.", |
|||
}, |
|||
|
|||
// Giver/Recipient errors
|
|||
GIVER_RECIPIENT_ERRORS: { |
|||
MISSING_GIVER: "To assign a giver, you must open this page from a contact.", |
|||
CONFLICT_PROJECT_GIVER: "You cannot assign both a giver and a project.", |
|||
MISSING_RECIPIENT_GIFT: |
|||
"To assign to a recipient, you must open this page from a contact.", |
|||
CONFLICT_PROJECT_RECIPIENT: |
|||
"You cannot assign both to a recipient and to a project.", |
|||
MISSING_PROVIDER_PROJECT: |
|||
"To select a project as a provider, you must open this page through a project.", |
|||
CONFLICT_GIVING_PROJECT: |
|||
"You cannot select both a giving project and person.", |
|||
MISSING_FULFILLS_PROJECT: |
|||
"To assign to a project, you must open this page through a project.", |
|||
CONFLICT_FULFILLS_PROJECT: |
|||
"You cannot assign both to a project and to a recipient.", |
|||
}, |
|||
} as const; |
|||
|
|||
// Type for accessing constants
|
|||
export type AccountViewConstants = typeof ACCOUNT_VIEW_CONSTANTS; |
|||
|
|||
// Helper type for error messages
|
|||
export type ErrorMessageKey = keyof typeof ACCOUNT_VIEW_CONSTANTS.ERRORS; |
|||
export type SuccessMessageKey = keyof typeof ACCOUNT_VIEW_CONSTANTS.SUCCESS; |
|||
export type InfoMessageKey = keyof typeof ACCOUNT_VIEW_CONSTANTS.INFO; |
|||
export type WarningMessageKey = keyof typeof ACCOUNT_VIEW_CONSTANTS.WARNINGS; |
@ -0,0 +1,232 @@ |
|||
/** |
|||
* TypeScript interfaces for AccountViewView component |
|||
* Provides type safety for settings, profile data, and component state |
|||
*/ |
|||
|
|||
import { EndorserRateLimits, ImageRateLimits } from "./index"; |
|||
import { LeafletMouseEvent } from "leaflet"; |
|||
|
|||
/** |
|||
* BoundingBox type describes the geographical bounding box coordinates. |
|||
*/ |
|||
export type BoundingBox = { |
|||
eastLong: number; // Eastern longitude
|
|||
maxLat: number; // Maximum (Northernmost) latitude
|
|||
minLat: number; // Minimum (Southernmost) latitude
|
|||
westLong: number; // Western longitude
|
|||
}; |
|||
|
|||
/** |
|||
* Interface for account settings retrieved from database |
|||
*/ |
|||
export interface AccountSettings { |
|||
activeDid?: string; |
|||
apiServer?: string; |
|||
firstName?: string; |
|||
lastName?: string; |
|||
hideRegisterPromptOnNewContact?: boolean; |
|||
isRegistered?: boolean; |
|||
searchBoxes?: Array<{ |
|||
name: string; |
|||
bbox: BoundingBox; |
|||
}>; |
|||
notifyingNewActivityTime?: string; |
|||
notifyingReminderMessage?: string; |
|||
notifyingReminderTime?: string; |
|||
partnerApiServer?: string; |
|||
profileImageUrl?: string; |
|||
showContactGivesInline?: boolean; |
|||
passkeyExpirationMinutes?: number; |
|||
showGeneralAdvanced?: boolean; |
|||
showShortcutBvc?: boolean; |
|||
warnIfProdServer?: boolean; |
|||
warnIfTestServer?: boolean; |
|||
webPushServer?: string; |
|||
} |
|||
|
|||
/** |
|||
* Interface for user profile data from API |
|||
*/ |
|||
export interface UserProfileData { |
|||
description?: string; |
|||
locLat?: number; |
|||
locLon?: number; |
|||
} |
|||
|
|||
/** |
|||
* Interface for API response containing user profile |
|||
*/ |
|||
export interface UserProfileResponse { |
|||
data: UserProfileData; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to profile management |
|||
*/ |
|||
export interface ProfileState { |
|||
userProfileDesc: string; |
|||
userProfileLatitude: number; |
|||
userProfileLongitude: number; |
|||
includeUserProfileLocation: boolean; |
|||
savingProfile: boolean; |
|||
profileImageUrl?: string; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to notifications |
|||
*/ |
|||
export interface NotificationState { |
|||
notifyingNewActivity: boolean; |
|||
notifyingNewActivityTime: string; |
|||
notifyingReminder: boolean; |
|||
notifyingReminderMessage: string; |
|||
notifyingReminderTime: string; |
|||
subscription: PushSubscription | null; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to settings |
|||
*/ |
|||
export interface SettingsState { |
|||
activeDid: string; |
|||
apiServer: string; |
|||
apiServerInput: string; |
|||
partnerApiServer: string; |
|||
partnerApiServerInput: string; |
|||
webPushServer: string; |
|||
webPushServerInput: string; |
|||
passkeyExpirationMinutes: number; |
|||
previousPasskeyExpirationMinutes: number; |
|||
passkeyExpirationDescription: string; |
|||
hideRegisterPromptOnNewContact: boolean; |
|||
isRegistered: boolean; |
|||
isSearchAreasSet: boolean; |
|||
showContactGives: boolean; |
|||
showGeneralAdvanced: boolean; |
|||
showShortcutBvc: boolean; |
|||
warnIfProdServer: boolean; |
|||
warnIfTestServer: boolean; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to UI display |
|||
*/ |
|||
export interface UIState { |
|||
loadingProfile: boolean; |
|||
loadingLimits: boolean; |
|||
showAdvanced: boolean; |
|||
showB64Copy: boolean; |
|||
showDidCopy: boolean; |
|||
showDerCopy: boolean; |
|||
showPubCopy: boolean; |
|||
showLargeIdenticonId?: string; |
|||
showLargeIdenticonUrl?: string; |
|||
downloadUrl: string; |
|||
zoom: number; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to limits and validation |
|||
*/ |
|||
export interface LimitsState { |
|||
endorserLimits: EndorserRateLimits | null; |
|||
imageLimits: ImageRateLimits | null; |
|||
limitsMessage: string; |
|||
publicHex: string; |
|||
publicBase64: string; |
|||
derivationPath: string; |
|||
} |
|||
|
|||
/** |
|||
* Interface for component state related to identity |
|||
*/ |
|||
export interface IdentityState { |
|||
givenName: string; |
|||
} |
|||
|
|||
/** |
|||
* Complete interface for AccountViewView component state |
|||
*/ |
|||
export interface AccountViewState |
|||
extends ProfileState, |
|||
NotificationState, |
|||
SettingsState, |
|||
UIState, |
|||
LimitsState, |
|||
IdentityState {} |
|||
|
|||
/** |
|||
* Interface for clipboard copy operations |
|||
*/ |
|||
export interface ClipboardOperation { |
|||
text: string; |
|||
callback: () => void; |
|||
} |
|||
|
|||
/** |
|||
* Interface for notification permission callback |
|||
*/ |
|||
export interface NotificationPermissionCallback { |
|||
success: boolean; |
|||
timeText: string; |
|||
message?: string; |
|||
} |
|||
|
|||
/** |
|||
* Interface for import/export operations |
|||
*/ |
|||
export interface ImportExportState { |
|||
inputImportFileNameRef?: Blob; |
|||
} |
|||
|
|||
/** |
|||
* Type for API error responses |
|||
*/ |
|||
export interface ApiErrorResponse { |
|||
response?: { |
|||
data?: { |
|||
error?: { message?: string } | string; |
|||
}; |
|||
status?: number; |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* Type guard for API errors |
|||
*/ |
|||
export function isApiError(error: unknown): error is ApiErrorResponse { |
|||
return typeof error === "object" && error !== null && "response" in error; |
|||
} |
|||
|
|||
/** |
|||
* Type guard for standard errors |
|||
*/ |
|||
export function isError(error: unknown): error is Error { |
|||
return error instanceof Error; |
|||
} |
|||
|
|||
/** |
|||
* Interface for file import content structure |
|||
*/ |
|||
export interface ImportContent { |
|||
data?: { |
|||
data?: Array<{ |
|||
tableName: string; |
|||
rows: Array<unknown>; |
|||
}>; |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* Interface for map ready callback |
|||
*/ |
|||
export interface MapReadyCallback { |
|||
(map: L.Map): void; |
|||
} |
|||
|
|||
/** |
|||
* Interface for mouse event handlers |
|||
*/ |
|||
export interface MouseEventHandler { |
|||
(event: LeafletMouseEvent): void; |
|||
} |
Loading…
Reference in new issue