Browse Source

Merge branch 'build-improvement' into units-mocking

pull/153/head
Matthew Raymer 3 weeks ago
parent
commit
8e0b339095
  1. 28
      src/components/ActivityListItem.vue
  2. 17
      src/components/ContactBulkActions.vue
  3. 4
      src/components/ContactInputForm.vue
  4. 38
      src/components/ContactListHeader.vue
  5. 33
      src/components/ContactListItem.vue
  6. 2
      src/components/ImageViewer.vue
  7. 10
      src/components/LargeIdenticonModal.vue
  8. 16
      src/components/MembersList.vue
  9. 2
      src/components/OnboardingDialog.vue
  10. 2
      src/components/UsageLimitsSection.vue
  11. 4
      src/db/tables/contacts.ts
  12. 1
      src/libs/util.ts
  13. 202
      src/utils/PlatformServiceMixin.ts
  14. 10
      src/views/AccountViewView.vue
  15. 1
      src/views/HomeView.vue

28
src/components/ActivityListItem.vue

@ -52,7 +52,7 @@
<a <a
class="cursor-pointer" class="cursor-pointer"
data-testid="circle-info-link" data-testid="circle-info-link"
@click="$emit('loadClaim', record.jwtId)" @click="emitLoadClaim(record.jwtId)"
> >
<font-awesome icon="circle-info" class="fa-fw text-slate-500" /> <font-awesome icon="circle-info" class="fa-fw text-slate-500" />
</a> </a>
@ -67,7 +67,7 @@
> >
<a <a
class="block bg-slate-100/50 backdrop-blur-md px-6 py-4 cursor-pointer" class="block bg-slate-100/50 backdrop-blur-md px-6 py-4 cursor-pointer"
@click="$emit('viewImage', record.image)" @click="emitViewImage(record.image)"
> >
<img <img
class="w-full h-auto max-w-lg max-h-96 object-contain mx-auto drop-shadow-md" class="w-full h-auto max-w-lg max-h-96 object-contain mx-auto drop-shadow-md"
@ -80,7 +80,7 @@
<!-- Description --> <!-- Description -->
<p class="font-medium"> <p class="font-medium">
<a class="cursor-pointer" @click="$emit('loadClaim', record.jwtId)"> <a class="cursor-pointer" @click="emitLoadClaim(record.jwtId)">
{{ description }} {{ description }}
</a> </a>
</p> </p>
@ -248,7 +248,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-facing-decorator"; import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
import { GiveRecordWithContactInfo } from "@/interfaces/give"; import { GiveRecordWithContactInfo } from "@/interfaces/give";
import EntityIcon from "./EntityIcon.vue"; import EntityIcon from "./EntityIcon.vue";
import { isGiveClaimType, notifyWhyCannotConfirm } from "../libs/util"; import { isGiveClaimType, notifyWhyCannotConfirm } from "../libs/util";
@ -340,7 +340,19 @@ export default class ActivityListItem extends Vue {
return true; return true;
} }
handleConfirmClick() { // Emit methods using @Emit decorator
@Emit("viewImage")
emitViewImage(imageUrl: string) {
return imageUrl;
}
@Emit("loadClaim")
emitLoadClaim(jwtId: string) {
return jwtId;
}
@Emit("confirmClaim")
emitConfirmClaim() {
if (!this.canConfirm) { if (!this.canConfirm) {
notifyWhyCannotConfirm( notifyWhyCannotConfirm(
(msg, timeout) => this.notify.info(msg.text ?? "", timeout), (msg, timeout) => this.notify.info(msg.text ?? "", timeout),
@ -352,7 +364,11 @@ export default class ActivityListItem extends Vue {
); );
return; return;
} }
this.$emit("confirmClaim", this.record); return this.record;
}
handleConfirmClick() {
this.emitConfirmClaim();
} }
get friendlyDate(): string { get friendlyDate(): string {

17
src/components/ContactBulkActions.vue

@ -6,13 +6,13 @@
:checked="allContactsSelected" :checked="allContactsSelected"
class="align-middle ml-2 h-6 w-6" class="align-middle ml-2 h-6 w-6"
data-testId="contactCheckAllBottom" data-testId="contactCheckAllBottom"
@click="$emit('toggle-all-selection')" @click="emitToggleAllSelection"
/> />
<button <button
v-if="!showGiveNumbers" v-if="!showGiveNumbers"
:class="copyButtonClass" :class="copyButtonClass"
:disabled="copyButtonDisabled" :disabled="copyButtonDisabled"
@click="$emit('copy-selected')" @click="emitCopySelected"
> >
Copy Copy
</button> </button>
@ -20,7 +20,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
/** /**
* ContactBulkActions - Contact bulk actions component * ContactBulkActions - Contact bulk actions component
@ -38,5 +38,16 @@ export default class ContactBulkActions extends Vue {
@Prop({ required: true }) allContactsSelected!: boolean; @Prop({ required: true }) allContactsSelected!: boolean;
@Prop({ required: true }) copyButtonClass!: string; @Prop({ required: true }) copyButtonClass!: string;
@Prop({ required: true }) copyButtonDisabled!: boolean; @Prop({ required: true }) copyButtonDisabled!: boolean;
// Emit methods using @Emit decorator
@Emit("toggle-all-selection")
emitToggleAllSelection() {
// No parameters needed
}
@Emit("copy-selected")
emitCopySelected() {
// No parameters needed
}
} }
</script> </script>

4
src/components/ContactInputForm.vue

@ -64,7 +64,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
/** /**
* ContactInputForm - Contact input form component * ContactInputForm - Contact input form component
@ -165,9 +165,9 @@ export default class ContactInputForm extends Vue {
* Handle QR scan button click * Handle QR scan button click
* Emits qr-scan event for parent handling * Emits qr-scan event for parent handling
*/ */
@Emit("qr-scan")
private handleQRScan(): void { private handleQRScan(): void {
console.log("[ContactInputForm] QR scan button clicked"); console.log("[ContactInputForm] QR scan button clicked");
this.$emit("qr-scan");
} }
} }
</script> </script>

38
src/components/ContactListHeader.vue

@ -8,21 +8,21 @@
:checked="allContactsSelected" :checked="allContactsSelected"
class="align-middle ml-2 h-6 w-6" class="align-middle ml-2 h-6 w-6"
data-testId="contactCheckAllTop" data-testId="contactCheckAllTop"
@click="$emit('toggle-all-selection')" @click="emitToggleAllSelection"
/> />
<button <button
v-if="!showGiveNumbers" v-if="!showGiveNumbers"
:class="copyButtonClass" :class="copyButtonClass"
:disabled="copyButtonDisabled" :disabled="copyButtonDisabled"
data-testId="copySelectedContactsButtonTop" data-testId="copySelectedContactsButtonTop"
@click="$emit('copy-selected')" @click="emitCopySelected"
> >
Copy Copy
</button> </button>
<font-awesome <font-awesome
icon="circle-info" icon="circle-info"
class="text-2xl text-blue-500 ml-2" class="text-2xl text-blue-500 ml-2"
@click="$emit('show-copy-info')" @click="emitShowCopyInfo"
/> />
</div> </div>
</div> </div>
@ -33,7 +33,7 @@
v-if="showGiveNumbers" v-if="showGiveNumbers"
class="text-md bg-gradient-to-b shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md" class="text-md bg-gradient-to-b shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
:class="giveAmountsButtonClass" :class="giveAmountsButtonClass"
@click="$emit('toggle-give-totals')" @click="emitToggleGiveTotals"
> >
{{ giveAmountsButtonText }} {{ giveAmountsButtonText }}
<font-awesome icon="left-right" class="fa-fw" /> <font-awesome icon="left-right" class="fa-fw" />
@ -41,7 +41,7 @@
<button <button
class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md" class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
@click="$emit('toggle-show-actions')" @click="emitToggleShowActions"
> >
{{ showActionsButtonText }} {{ showActionsButtonText }}
</button> </button>
@ -50,7 +50,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
/** /**
* ContactListHeader - Contact list header component * ContactListHeader - Contact list header component
@ -71,5 +71,31 @@ export default class ContactListHeader extends Vue {
@Prop({ required: true }) giveAmountsButtonText!: string; @Prop({ required: true }) giveAmountsButtonText!: string;
@Prop({ required: true }) showActionsButtonText!: string; @Prop({ required: true }) showActionsButtonText!: string;
@Prop({ required: true }) giveAmountsButtonClass!: Record<string, boolean>; @Prop({ required: true }) giveAmountsButtonClass!: Record<string, boolean>;
// Emit methods using @Emit decorator
@Emit("toggle-all-selection")
emitToggleAllSelection() {
// No parameters needed
}
@Emit("copy-selected")
emitCopySelected() {
// No parameters needed
}
@Emit("show-copy-info")
emitShowCopyInfo() {
// No parameters needed
}
@Emit("toggle-give-totals")
emitToggleGiveTotals() {
// No parameters needed
}
@Emit("toggle-show-actions")
emitToggleShowActions() {
// No parameters needed
}
} }
</script> </script>

33
src/components/ContactListItem.vue

@ -9,14 +9,14 @@
:checked="isSelected" :checked="isSelected"
class="ml-2 h-6 w-6 flex-shrink-0" class="ml-2 h-6 w-6 flex-shrink-0"
data-testId="contactCheckOne" data-testId="contactCheckOne"
@click="$emit('toggle-selection', contact.did)" @click="emitToggleSelection(contact.did)"
/> />
<EntityIcon <EntityIcon
:contact="contact" :contact="contact"
:icon-size="48" :icon-size="48"
class="shrink-0 align-text-bottom border border-slate-300 rounded cursor-pointer overflow-hidden" class="shrink-0 align-text-bottom border border-slate-300 rounded cursor-pointer overflow-hidden"
@click="$emit('show-identicon', contact)" @click="emitShowIdenticon(contact)"
/> />
<div class="overflow-hidden"> <div class="overflow-hidden">
@ -63,7 +63,7 @@
<button <button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2.5 py-1.5 rounded-l-md" class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2.5 py-1.5 rounded-l-md"
:title="getGiveDescriptionForContact(contact.did, true)" :title="getGiveDescriptionForContact(contact.did, true)"
@click="$emit('show-gifted-dialog', contact.did, activeDid)" @click="emitShowGiftedDialog(contact.did, activeDid)"
> >
{{ getGiveAmountForContact(contact.did, true) }} {{ getGiveAmountForContact(contact.did, true) }}
</button> </button>
@ -71,7 +71,7 @@
<button <button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2.5 py-1.5 rounded-r-md border-l" class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2.5 py-1.5 rounded-r-md border-l"
:title="getGiveDescriptionForContact(contact.did, false)" :title="getGiveDescriptionForContact(contact.did, false)"
@click="$emit('show-gifted-dialog', activeDid, contact.did)" @click="emitShowGiftedDialog(activeDid, contact.did)"
> >
{{ getGiveAmountForContact(contact.did, false) }} {{ getGiveAmountForContact(contact.did, false) }}
</button> </button>
@ -81,7 +81,7 @@
<button <button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md" class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md"
data-testId="offerButton" data-testId="offerButton"
@click="$emit('open-offer-dialog', contact.did, contact.name)" @click="emitOpenOfferDialog(contact.did, contact.name)"
> >
Offer Offer
</button> </button>
@ -102,7 +102,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, 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 { AppString } from "../constants/app"; import { AppString } from "../constants/app";
@ -140,6 +140,27 @@ export default class ContactListItem extends Vue {
// Constants // Constants
AppString = AppString; AppString = AppString;
// Emit methods using @Emit decorator
@Emit("toggle-selection")
emitToggleSelection(did: string) {
return did;
}
@Emit("show-identicon")
emitShowIdenticon(contact: Contact) {
return contact;
}
@Emit("show-gifted-dialog")
emitShowGiftedDialog(fromDid: string, toDid: string) {
return { fromDid, toDid };
}
@Emit("open-offer-dialog")
emitOpenOfferDialog(did: string, name: string | undefined) {
return { did, name };
}
/** /**
* Format contact name with non-breaking spaces * Format contact name with non-breaking spaces
*/ */

2
src/components/ImageViewer.vue

@ -25,7 +25,7 @@
<div class="flex-1 flex items-center justify-center p-2"> <div class="flex-1 flex items-center justify-center p-2">
<div class="w-full h-full flex items-center justify-center"> <div class="w-full h-full flex items-center justify-center">
<img <img
:src="transformedImageUrl" :src="imageUrl"
class="max-h-[calc(100vh-5rem)] w-full h-full object-contain" class="max-h-[calc(100vh-5rem)] w-full h-full object-contain"
alt="expanded shared content" alt="expanded shared content"
@click="close" @click="close"

10
src/components/LargeIdenticonModal.vue

@ -7,14 +7,14 @@
:contact="contact" :contact="contact"
:icon-size="512" :icon-size="512"
class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg" class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
@click="$emit('close')" @click="emitClose"
/> />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, 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";
@ -34,5 +34,11 @@ import { Contact } from "../db/tables/contacts";
}) })
export default class LargeIdenticonModal extends Vue { export default class LargeIdenticonModal extends Vue {
@Prop({ required: true }) contact!: Contact | undefined; @Prop({ required: true }) contact!: Contact | undefined;
// Emit methods using @Emit decorator
@Emit("close")
emitClose() {
// No parameters needed
}
} }
</script> </script>

16
src/components/MembersList.vue

@ -178,7 +178,7 @@
// Validation: Passes lint checks and TypeScript compilation // Validation: Passes lint checks and TypeScript compilation
// Navigation: Contacts Chair Icon Start/Join Meeting Members List // Navigation: Contacts Chair Icon Start/Join Meeting Members List
import { Component, Vue, Prop } from "vue-facing-decorator"; import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
import { import {
errorStringForLog, errorStringForLog,
@ -222,6 +222,12 @@ export default class MembersList extends Vue {
@Prop({ required: true }) password!: string; @Prop({ required: true }) password!: string;
@Prop({ default: false }) showOrganizerTools!: boolean; @Prop({ default: false }) showOrganizerTools!: boolean;
// Emit methods using @Emit decorator
@Emit("error")
emitError(message: string) {
return message;
}
decryptedMembers: DecryptedMember[] = []; decryptedMembers: DecryptedMember[] = [];
firstName = ""; firstName = "";
isLoading = true; isLoading = true;
@ -262,10 +268,7 @@ export default class MembersList extends Vue {
"Error fetching members: " + errorStringForLog(error), "Error fetching members: " + errorStringForLog(error),
true, true,
); );
this.$emit( this.emitError(serverMessageForUser(error) || "Failed to fetch members.");
"error",
serverMessageForUser(error) || "Failed to fetch members.",
);
} finally { } finally {
this.isLoading = false; this.isLoading = false;
} }
@ -478,8 +481,7 @@ export default class MembersList extends Vue {
"Error toggling admission: " + errorStringForLog(error), "Error toggling admission: " + errorStringForLog(error),
true, true,
); );
this.$emit( this.emitError(
"error",
serverMessageForUser(error) || serverMessageForUser(error) ||
"Failed to update member admission status.", "Failed to update member admission status.",
); );

2
src/components/OnboardingDialog.vue

@ -180,7 +180,7 @@
> >
Let's go! Let's go!
<br /> <br />
See & record gratitude. See & record things you've received.
</button> </button>
<button <button
type="button" type="button"

2
src/components/UsageLimitsSection.vue

@ -67,7 +67,7 @@
out of <b>{{ imageLimits?.maxImagesPerWeek ?? "?" }}</b> for this week. out of <b>{{ imageLimits?.maxImagesPerWeek ?? "?" }}</b> for this week.
Your image counter resets at Your image counter resets at
<b class="whitespace-nowrap">{{ <b class="whitespace-nowrap">{{
readableDate(imageLimits?.nextWeekBeginDateTime || "") readableDate(imageLimits?.nextWeekBeginDateTime)
}}</b> }}</b>
</p> </p>
</div> </div>

4
src/db/tables/contacts.ts

@ -6,7 +6,9 @@ export type ContactMethod = {
export type Contact = { export type Contact = {
// //
// When adding a property, consider whether it should be added when exporting & sharing contacts, eg. DataExportSection // When adding a property:
// - Consider whether it should be added when exporting & sharing contacts, eg. DataExportSection
// - If it's a boolean, it should be converted from a 0/1 integer in PlatformServiceMixin._mapColumnsToValues
did: string; did: string;
contactMethods?: Array<ContactMethod>; contactMethods?: Array<ContactMethod>;

1
src/libs/util.ts

@ -34,6 +34,7 @@ import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { DEFAULT_ROOT_DERIVATION_PATH } from "./crypto"; import { DEFAULT_ROOT_DERIVATION_PATH } from "./crypto";
// Consolidate this with src/utils/PlatformServiceMixin._parseJsonField
function parseJsonField<T>(value: unknown, defaultValue: T): T { function parseJsonField<T>(value: unknown, defaultValue: T): T {
if (typeof value === "string") { if (typeof value === "string") {
try { try {

202
src/utils/PlatformServiceMixin.ts

@ -59,14 +59,14 @@ import {
// TYPESCRIPT INTERFACES // TYPESCRIPT INTERFACES
// ================================================= // =================================================
/** // /**
* Cache entry interface for storing data with TTL // * Cache entry interface for storing data with TTL
*/ // */
interface CacheEntry<T> { // interface CacheEntry<T> {
data: T; // data: T;
timestamp: number; // timestamp: number;
ttl: number; // milliseconds // ttl: number; // milliseconds
} // }
/** /**
* Vue component interface that uses the PlatformServiceMixin * Vue component interface that uses the PlatformServiceMixin
@ -79,21 +79,21 @@ interface VueComponentWithMixin {
platformService(): PlatformService; platformService(): PlatformService;
} }
/** // /**
* Global cache store for mixin instances // * Global cache store for mixin instances
* Uses WeakMap to avoid memory leaks when components are destroyed // * Uses WeakMap to avoid memory leaks when components are destroyed
*/ // */
const componentCaches = new WeakMap< // const componentCaches = new WeakMap<
VueComponentWithMixin, // VueComponentWithMixin,
Map<string, CacheEntry<unknown>> // Map<string, CacheEntry<unknown>>
>(); // >();
//
/** // /**
* Cache configuration constants // * Cache configuration constants
*/ // */
const CACHE_DEFAULTS = { // const CACHE_DEFAULTS = {
default: 15000, // 15 seconds default TTL // default: 15000, // 15 seconds default TTL
} as const; // } as const;
const _memoryLogs: string[] = []; const _memoryLogs: string[] = [];
@ -178,8 +178,8 @@ export const PlatformServiceMixin = {
logger.debug( logger.debug(
`[PlatformServiceMixin] ActiveDid changed from ${oldDid} to ${newDid}`, `[PlatformServiceMixin] ActiveDid changed from ${oldDid} to ${newDid}`,
); );
// Clear caches that might be affected by the change // // Clear caches that might be affected by the change
(this as any).$clearAllCaches(); // (this as any).$clearAllCaches();
} }
}, },
immediate: true, immediate: true,
@ -203,8 +203,8 @@ export const PlatformServiceMixin = {
logger.debug( logger.debug(
`[PlatformServiceMixin] ActiveDid updated from ${oldDid} to ${newDid}`, `[PlatformServiceMixin] ActiveDid updated from ${oldDid} to ${newDid}`,
); );
// Clear caches that might be affected by the change // // Clear caches that might be affected by the change
this.$clearAllCaches(); // this.$clearAllCaches();
} }
}, },
@ -251,6 +251,8 @@ export const PlatformServiceMixin = {
/** /**
* Self-contained implementation of parseJsonField * Self-contained implementation of parseJsonField
* Safely parses JSON strings with fallback to default value * Safely parses JSON strings with fallback to default value
*
* Consolidate this with src/libs/util.ts parseJsonField
*/ */
_parseJsonField<T>(value: unknown, defaultValue: T): T { _parseJsonField<T>(value: unknown, defaultValue: T): T {
if (typeof value === "string") { if (typeof value === "string") {
@ -263,71 +265,71 @@ export const PlatformServiceMixin = {
return (value as T) || defaultValue; return (value as T) || defaultValue;
}, },
// ================================================= // // =================================================
// CACHING UTILITY METHODS // // CACHING UTILITY METHODS
// ================================================= // // =================================================
/** // /**
* Get or initialize cache for this component instance // * Get or initialize cache for this component instance
*/ // */
_getCache(): Map<string, CacheEntry<unknown>> { // _getCache(): Map<string, CacheEntry<unknown>> {
let cache = componentCaches.get(this as unknown as VueComponentWithMixin); // let cache = componentCaches.get(this as unknown as VueComponentWithMixin);
if (!cache) { // if (!cache) {
cache = new Map(); // cache = new Map();
componentCaches.set(this as unknown as VueComponentWithMixin, cache); // componentCaches.set(this as unknown as VueComponentWithMixin, cache);
} // }
return cache; // return cache;
}, // },
/** // /**
* Check if cache entry is valid (not expired) // * Check if cache entry is valid (not expired)
*/ // */
_isCacheValid(entry: CacheEntry<unknown>): boolean { // _isCacheValid(entry: CacheEntry<unknown>): boolean {
return Date.now() - entry.timestamp < entry.ttl; // return Date.now() - entry.timestamp < entry.ttl;
}, // },
/** // /**
* Get data from cache if valid, otherwise return null // * Get data from cache if valid, otherwise return null
*/ // */
_getCached<T>(key: string): T | null { // _getCached<T>(key: string): T | null {
const cache = this._getCache(); // const cache = this._getCache();
const entry = cache.get(key); // const entry = cache.get(key);
if (entry && this._isCacheValid(entry)) { // if (entry && this._isCacheValid(entry)) {
return entry.data as T; // return entry.data as T;
} // }
cache.delete(key); // Clean up expired entries // cache.delete(key); // Clean up expired entries
return null; // return null;
}, // },
/** // /**
* Store data in cache with TTL // * Store data in cache with TTL
*/ // */
_setCached<T>(key: string, data: T, ttl?: number): T { // _setCached<T>(key: string, data: T, ttl?: number): T {
const cache = this._getCache(); // const cache = this._getCache();
const actualTtl = ttl || CACHE_DEFAULTS.default; // const actualTtl = ttl || CACHE_DEFAULTS.default;
cache.set(key, { // cache.set(key, {
data, // data,
timestamp: Date.now(), // timestamp: Date.now(),
ttl: actualTtl, // ttl: actualTtl,
}); // });
return data; // return data;
}, // },
/** // /**
* Invalidate specific cache entry // * Invalidate specific cache entry
*/ // */
_invalidateCache(key: string): void { // _invalidateCache(key: string): void {
const cache = this._getCache(); // const cache = this._getCache();
cache.delete(key); // cache.delete(key);
}, // },
/** // /**
* Clear all cache entries for this component // * Clear all cache entries for this component
*/ // */
_clearCache(): void { // _clearCache(): void {
const cache = this._getCache(); // const cache = this._getCache();
cache.clear(); // cache.clear();
}, // },
// ================================================= // =================================================
// ENHANCED DATABASE METHODS (with error handling) // ENHANCED DATABASE METHODS (with error handling)
@ -879,13 +881,13 @@ export const PlatformServiceMixin = {
return await this.$contacts(); return await this.$contacts();
}, },
/** // /**
* Clear all caches for this component - $clearAllCaches() // * Clear all caches for this component - $clearAllCaches()
* Useful for manual cache management // * Useful for manual cache management
*/ // */
$clearAllCaches(): void { // $clearAllCaches(): void {
this._clearCache(); // this._clearCache();
}, // },
// ================================================= // =================================================
// HIGH-LEVEL ENTITY OPERATIONS (eliminate verbose SQL patterns) // HIGH-LEVEL ENTITY OPERATIONS (eliminate verbose SQL patterns)
@ -1657,7 +1659,7 @@ declare module "@vue/runtime-core" {
// Cache management methods // Cache management methods
$refreshSettings(): Promise<Settings>; $refreshSettings(): Promise<Settings>;
$refreshContacts(): Promise<Contact[]>; $refreshContacts(): Promise<Contact[]>;
$clearAllCaches(): void; // $clearAllCaches(): void;
// High-level entity operations (eliminate verbose SQL patterns) // High-level entity operations (eliminate verbose SQL patterns)
$mapResults<T>( $mapResults<T>(

10
src/views/AccountViewView.vue

@ -1396,10 +1396,6 @@ export default class AccountViewView extends Vue {
if (imageResp.status === 200) { if (imageResp.status === 200) {
this.imageLimits = imageResp.data; this.imageLimits = imageResp.data;
} else { } else {
await this.$saveSettings({
profileImageUrl: "",
});
this.profileImageUrl = "";
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS;
this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES); this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES);
return; return;
@ -1414,10 +1410,6 @@ export default class AccountViewView extends Vue {
if (endorserResp.status === 200) { if (endorserResp.status === 200) {
this.endorserLimits = endorserResp.data; this.endorserLimits = endorserResp.data;
} else { } else {
await this.$saveSettings({
profileImageUrl: "",
});
this.profileImageUrl = "";
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND;
this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE); this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE);
return; return;
@ -1425,7 +1417,7 @@ export default class AccountViewView extends Vue {
} catch (error) { } catch (error) {
this.limitsMessage = this.limitsMessage =
ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS; ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS;
console.log("error: ", error); logger.error("Error retrieving limits: ", error);
// this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD); // this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD);
} finally { } finally {
this.loadingLimits = false; this.loadingLimits = false;

1
src/views/HomeView.vue

@ -314,6 +314,7 @@ import {
} from "@/constants/notifications"; } from "@/constants/notifications";
import * as Package from "../../package.json"; import * as Package from "../../package.json";
// consolidate this with GiveActionClaim in src/interfaces/claims.ts
interface Claim { interface Claim {
claim?: Claim; // For nested claims in Verifiable Credentials claim?: Claim; // For nested claims in Verifiable Credentials
agent?: { agent?: {

Loading…
Cancel
Save