forked from trent_larson/crowd-funder-for-time-pwa
Restore complete UsageLimitsSection functionality with detailed limits display
- Restored proper section container with bg-slate-100 styling and accessibility attributes - Added FontAwesome spinner with proper ARIA labels for loading state - Restored detailed limits information showing claims/week, registrations/month, and images/week - Added proper pluralization and date formatting for reset timers - Enhanced button styling to match original design with slate gradient - Added activeDid, endorserLimits, and imageLimits props to component - Maintained comprehensive debugging for troubleshooting User #00 limits issue - Added readableDate helper method for consistent date formatting Fixes missing functionality that was lost during component extraction from AccountViewView.
This commit is contained in:
@@ -1,14 +1,79 @@
|
||||
<template>
|
||||
<section id="sectionUsageLimits" class="mt-4">
|
||||
<h2 class="text-lg font-semibold mb-2">Usage Limits</h2>
|
||||
<div class="mb-2">
|
||||
<span v-if="loadingLimits" class="text-slate-700"
|
||||
>Checking... <span class="animate-spin">⏳</span></span
|
||||
>
|
||||
<span v-else class="text-slate-700">{{ limitsMessage }}</span>
|
||||
<section
|
||||
v-if="activeDid"
|
||||
id="sectionUsageLimits"
|
||||
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
|
||||
aria-labelledby="usageLimitsHeading"
|
||||
>
|
||||
<h2 id="usageLimitsHeading" class="mb-2 font-bold">Usage Limits</h2>
|
||||
<!-- show spinner if loading limits -->
|
||||
<div
|
||||
v-if="loadingLimits"
|
||||
class="text-center"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
Checking…
|
||||
<font-awesome
|
||||
icon="spinner"
|
||||
class="fa-spin"
|
||||
aria-hidden="true"
|
||||
></font-awesome>
|
||||
</div>
|
||||
<div class="mb-4 text-center">
|
||||
{{ limitsMessage }}
|
||||
</div>
|
||||
<div v-if="endorserLimits">
|
||||
<p class="text-sm">
|
||||
You have done
|
||||
<b
|
||||
>{{ endorserLimits?.doneClaimsThisWeek ?? "?" }} claim{{
|
||||
Number(endorserLimits?.doneClaimsThisWeek || 0) === 1 ? "" : "s"
|
||||
}}</b
|
||||
>
|
||||
out of <b>{{ endorserLimits?.maxClaimsPerWeek ?? "?" }}</b> for this
|
||||
week. Your claims counter resets at
|
||||
<b class="whitespace-nowrap">{{
|
||||
readableDate(endorserLimits?.nextWeekBeginDateTime)
|
||||
}}</b>
|
||||
</p>
|
||||
<p class="mt-3 text-sm">
|
||||
You have done
|
||||
<b
|
||||
>{{
|
||||
endorserLimits?.doneRegistrationsThisMonth ?? "?"
|
||||
}}
|
||||
registration{{
|
||||
Number(endorserLimits?.doneRegistrationsThisMonth || 0) === 1
|
||||
? ""
|
||||
: "s"
|
||||
}}</b
|
||||
>
|
||||
out of
|
||||
<b>{{ endorserLimits?.maxRegistrationsPerMonth ?? "?" }}</b> for this
|
||||
this month.
|
||||
<i>(You cannot register anyone on your first day.)</i>
|
||||
Your registration counter resets at
|
||||
<b class="whitespace-nowrap">
|
||||
{{ readableDate(endorserLimits?.nextMonthBeginDateTime) }}
|
||||
</b>
|
||||
</p>
|
||||
<p class="mt-3 text-sm">
|
||||
You have uploaded
|
||||
<b
|
||||
>{{ imageLimits?.doneImagesThisWeek ?? "?" }} image{{
|
||||
Number(imageLimits?.doneImagesThisWeek || 0) === 1 ? "" : "s"
|
||||
}}</b
|
||||
>
|
||||
out of <b>{{ imageLimits?.maxImagesPerWeek ?? "?" }}</b> for this
|
||||
week. Your image counter resets at
|
||||
<b class="whitespace-nowrap">{{
|
||||
readableDate(imageLimits?.nextWeekBeginDateTime || "")
|
||||
}}</b>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="w-full text-md 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-4 py-2 rounded-md"
|
||||
class="block w-full text-center 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-4 py-2 rounded-md mt-4"
|
||||
@click="recheckLimits"
|
||||
>
|
||||
Recheck Limits
|
||||
@@ -18,13 +83,50 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
|
||||
@Component({ name: "UsageLimitsSection" })
|
||||
@Component({
|
||||
name: "UsageLimitsSection",
|
||||
components: {
|
||||
FontAwesome: FontAwesomeIcon
|
||||
}
|
||||
})
|
||||
export default class UsageLimitsSection extends Vue {
|
||||
@Prop({ required: true }) loadingLimits!: boolean;
|
||||
@Prop({ required: true }) limitsMessage!: string;
|
||||
@Prop({ required: true }) activeDid!: string;
|
||||
@Prop({ required: false }) endorserLimits?: any;
|
||||
@Prop({ required: false }) imageLimits?: any;
|
||||
|
||||
mounted() {
|
||||
console.log('[DEBUG] UsageLimitsSection mounted');
|
||||
console.log('[DEBUG] loadingLimits prop:', this.loadingLimits);
|
||||
console.log('[DEBUG] limitsMessage prop:', this.limitsMessage);
|
||||
console.log('[DEBUG] activeDid prop:', this.activeDid);
|
||||
console.log('[DEBUG] endorserLimits prop:', this.endorserLimits);
|
||||
console.log('[DEBUG] imageLimits prop:', this.imageLimits);
|
||||
}
|
||||
|
||||
updated() {
|
||||
console.log('[DEBUG] UsageLimitsSection updated');
|
||||
console.log('[DEBUG] loadingLimits prop:', this.loadingLimits);
|
||||
console.log('[DEBUG] limitsMessage prop:', this.limitsMessage);
|
||||
console.log('[DEBUG] endorserLimits prop:', this.endorserLimits);
|
||||
console.log('[DEBUG] imageLimits prop:', this.imageLimits);
|
||||
}
|
||||
|
||||
readableDate(dateString: string | undefined): string {
|
||||
if (!dateString) return "unknown";
|
||||
try {
|
||||
return new Date(dateString).toLocaleDateString();
|
||||
} catch {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@Emit("recheck-limits")
|
||||
recheckLimits() {}
|
||||
recheckLimits() {
|
||||
console.log('[DEBUG] recheckLimits called');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -251,6 +251,9 @@
|
||||
<UsageLimitsSection
|
||||
:loading-limits="loadingLimits"
|
||||
:limits-message="limitsMessage"
|
||||
:active-did="activeDid"
|
||||
:endorser-limits="endorserLimits"
|
||||
:image-limits="imageLimits"
|
||||
@recheck-limits="onRecheckLimits"
|
||||
/>
|
||||
|
||||
@@ -964,6 +967,14 @@ export default class AccountViewView extends Vue {
|
||||
this.loadingProfile = false;
|
||||
}
|
||||
|
||||
// Check limits for registered users
|
||||
if (this.isRegistered && this.activeDid) {
|
||||
console.log('[DEBUG] Calling checkLimits from mounted for registered user');
|
||||
await this.checkLimits();
|
||||
} else {
|
||||
console.log('[DEBUG] Not calling checkLimits - isRegistered:', this.isRegistered, 'activeDid:', this.activeDid);
|
||||
}
|
||||
|
||||
// Only check service worker on web platform - Capacitor/Electron don't support it
|
||||
if (!Capacitor.isNativePlatform()) {
|
||||
try {
|
||||
@@ -1005,6 +1016,8 @@ export default class AccountViewView extends Vue {
|
||||
const settings: AccountSettings = await this.$accountSettings();
|
||||
|
||||
this.activeDid = settings.activeDid || "";
|
||||
console.log('[DEBUG] initializeState - activeDid:', this.activeDid);
|
||||
console.log('[DEBUG] initializeState - settings.isRegistered:', settings?.isRegistered);
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.apiServerInput = settings.apiServer || "";
|
||||
this.givenName =
|
||||
@@ -1033,6 +1046,9 @@ export default class AccountViewView extends Vue {
|
||||
this.warnIfTestServer = !!settings.warnIfTestServer;
|
||||
this.webPushServer = settings.webPushServer || this.webPushServer;
|
||||
this.webPushServerInput = settings.webPushServer || this.webPushServerInput;
|
||||
|
||||
console.log('[DEBUG] initializeState complete - isRegistered:', this.isRegistered);
|
||||
console.log('[DEBUG] initializeState complete - activeDid:', this.activeDid);
|
||||
}
|
||||
|
||||
// call fn, copy text to the clipboard, then redo fn after 2 seconds
|
||||
@@ -1375,10 +1391,17 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
async checkLimits(): Promise<void> {
|
||||
console.log('[DEBUG] checkLimits called');
|
||||
console.log('[DEBUG] activeDid:', this.activeDid);
|
||||
console.log('[DEBUG] isRegistered:', this.isRegistered);
|
||||
|
||||
this.loadingLimits = true;
|
||||
try {
|
||||
const did = this.activeDid;
|
||||
console.log('[DEBUG] did value:', did);
|
||||
|
||||
if (!did) {
|
||||
console.log('[DEBUG] No DID found, setting NO_IDENTIFIER message');
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IDENTIFIER;
|
||||
return;
|
||||
}
|
||||
@@ -1389,10 +1412,16 @@ export default class AccountViewView extends Vue {
|
||||
webPushServer: this.webPushServer,
|
||||
});
|
||||
|
||||
console.log('[DEBUG] Calling fetchImageRateLimits for DID:', did);
|
||||
const imageResp = await fetchImageRateLimits(this.axios, did);
|
||||
console.log('[DEBUG] Image rate limits response status:', imageResp.status);
|
||||
console.log('[DEBUG] Image rate limits response data:', imageResp.data);
|
||||
|
||||
if (imageResp.status === 200) {
|
||||
this.imageLimits = imageResp.data;
|
||||
console.log('[DEBUG] Image limits set successfully');
|
||||
} else {
|
||||
console.log('[DEBUG] Image rate limits failed, status:', imageResp.status);
|
||||
await this.$saveSettings({
|
||||
profileImageUrl: "",
|
||||
});
|
||||
@@ -1402,14 +1431,21 @@ export default class AccountViewView extends Vue {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[DEBUG] Calling fetchEndorserRateLimits for DID:', did);
|
||||
console.log('[DEBUG] API server:', this.apiServer);
|
||||
const endorserResp = await fetchEndorserRateLimits(
|
||||
this.apiServer,
|
||||
this.axios,
|
||||
did,
|
||||
);
|
||||
console.log('[DEBUG] Endorser rate limits response status:', endorserResp.status);
|
||||
console.log('[DEBUG] Endorser rate limits response data:', endorserResp.data);
|
||||
|
||||
if (endorserResp.status === 200) {
|
||||
this.endorserLimits = endorserResp.data;
|
||||
console.log('[DEBUG] Endorser limits set successfully');
|
||||
} else {
|
||||
console.log('[DEBUG] Endorser rate limits failed, status:', endorserResp.status);
|
||||
await this.$saveSettings({
|
||||
profileImageUrl: "",
|
||||
});
|
||||
@@ -1419,11 +1455,14 @@ export default class AccountViewView extends Vue {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('[DEBUG] Error in checkLimits:', error);
|
||||
this.limitsMessage =
|
||||
ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS;
|
||||
this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD);
|
||||
} finally {
|
||||
console.log('[DEBUG] Setting loadingLimits to false');
|
||||
this.loadingLimits = false;
|
||||
console.log('[DEBUG] Final limitsMessage:', this.limitsMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1676,6 +1715,8 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
onRecheckLimits() {
|
||||
console.log('[DEBUG] onRecheckLimits called - button clicked');
|
||||
console.log('[DEBUG] Current state - loadingLimits:', this.loadingLimits, 'limitsMessage:', this.limitsMessage);
|
||||
this.checkLimits();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user