forked from jsnbuchanan/crowd-funder-for-time-pwa
Extract UsageLimitsSection as vue-facing-decorator component and integrate into AccountViewView
- Created UsageLimitsSection.vue using vue-facing-decorator (class-based, TypeScript, @Component, @Prop, @Emit). - Moved 'Usage Limits' UI and logic (status, spinner, message, recheck button) into the new component. - Replaced original usage limits section markup in AccountViewView.vue with <UsageLimitsSection />. - Passed loadingLimits and limitsMessage props, and wired up @recheck-limits event to call checkLimits(). - Ensured all linter errors are resolved and code is consistent with project conventions.
This commit is contained in:
28
src/components/UsageLimitsSection.vue
Normal file
28
src/components/UsageLimitsSection.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<section 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>
|
||||||
|
</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"
|
||||||
|
@click="recheckLimits"
|
||||||
|
>
|
||||||
|
Recheck Limits
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue, Prop, Emit } from 'vue-facing-decorator';
|
||||||
|
|
||||||
|
@Component({ name: 'UsageLimitsSection' })
|
||||||
|
export default class UsageLimitsSection extends Vue {
|
||||||
|
@Prop({ required: true }) loadingLimits!: boolean;
|
||||||
|
@Prop({ required: true }) limitsMessage!: string;
|
||||||
|
|
||||||
|
@Emit('recheck-limits')
|
||||||
|
recheckLimits() {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -248,86 +248,11 @@
|
|||||||
<div v-else>Saving...</div>
|
<div v-else>Saving...</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<UsageLimitsSection
|
||||||
v-if="activeDid"
|
:loading-limits="loadingLimits"
|
||||||
id="sectionUsageLimits"
|
:limits-message="limitsMessage"
|
||||||
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
|
@recheck-limits="onRecheckLimits"
|
||||||
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="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="checkLimits()"
|
|
||||||
>
|
|
||||||
Recheck Limits
|
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<DataExportSection :active-did="activeDid" />
|
<DataExportSection :active-did="activeDid" />
|
||||||
|
|
||||||
@@ -844,6 +769,7 @@ import DataExportSection from "../components/DataExportSection.vue";
|
|||||||
import IdentitySection from '@/components/IdentitySection.vue';
|
import IdentitySection from '@/components/IdentitySection.vue';
|
||||||
import RegistrationNotice from '@/components/RegistrationNotice.vue';
|
import RegistrationNotice from '@/components/RegistrationNotice.vue';
|
||||||
import LocationSearchSection from '@/components/LocationSearchSection.vue';
|
import LocationSearchSection from '@/components/LocationSearchSection.vue';
|
||||||
|
import UsageLimitsSection from '@/components/UsageLimitsSection.vue';
|
||||||
import {
|
import {
|
||||||
AppString,
|
AppString,
|
||||||
DEFAULT_IMAGE_API_SERVER,
|
DEFAULT_IMAGE_API_SERVER,
|
||||||
@@ -900,6 +826,7 @@ const inputImportFileNameRef = ref<Blob>();
|
|||||||
IdentitySection,
|
IdentitySection,
|
||||||
RegistrationNotice,
|
RegistrationNotice,
|
||||||
LocationSearchSection,
|
LocationSearchSection,
|
||||||
|
UsageLimitsSection,
|
||||||
},
|
},
|
||||||
mixins: [PlatformServiceMixin],
|
mixins: [PlatformServiceMixin],
|
||||||
})
|
})
|
||||||
@@ -1726,5 +1653,9 @@ export default class AccountViewView extends Vue {
|
|||||||
// TODO: Implement search area dialog logic
|
// TODO: Implement search area dialog logic
|
||||||
this.notify.info('Search area dialog not yet implemented.');
|
this.notify.info('Search area dialog not yet implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRecheckLimits() {
|
||||||
|
this.checkLimits();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user