monacousa-portal/components/DuesOverdueBanner.vue

171 lines
3.9 KiB
Vue
Raw Normal View History

<template>
<v-alert
v-if="overdueCount > 0"
type="warning"
variant="elevated"
class="dues-overdue-banner mb-6"
prominent
border="start"
>
<template #prepend>
<v-icon size="32">mdi-alert-circle</v-icon>
</template>
<template #title>
<span class="text-h6 font-weight-bold">
{{ overdueCount }} Member{{ overdueCount > 1 ? 's' : '' }} with Overdue Dues
</span>
</template>
<div class="mt-2">
<p class="mb-3">
{{ overdueCount }} member{{ overdueCount > 1 ? 's have' : ' has' }} dues that are more than 1 year overdue.
These accounts have been automatically marked as inactive.
</p>
<div class="d-flex flex-wrap gap-2 align-center">
<v-btn
color="warning"
variant="elevated"
size="small"
@click="$emit('view-overdue')"
>
<v-icon start>mdi-eye</v-icon>
View Overdue Members
</v-btn>
<v-btn
v-if="canUpdateStatuses"
color="primary"
variant="outlined"
size="small"
:loading="updatingStatuses"
@click="updateOverdueStatuses"
>
<v-icon start>mdi-refresh</v-icon>
Update Member Statuses
</v-btn>
<v-btn
v-if="canSendReminders"
color="secondary"
variant="outlined"
size="small"
@click="$emit('send-reminders')"
>
<v-icon start>mdi-email-multiple</v-icon>
Send Reminders
</v-btn>
<v-spacer />
<v-btn
icon
size="small"
variant="text"
@click="dismissed = true"
>
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</div>
</v-alert>
</template>
<script setup lang="ts">
interface Props {
overdueCount: number;
canUpdateStatuses?: boolean;
canSendReminders?: boolean;
refreshTrigger?: number;
}
interface Emits {
(e: 'view-overdue'): void;
(e: 'send-reminders'): void;
(e: 'statuses-updated', count: number): void;
}
const props = withDefaults(defineProps<Props>(), {
canUpdateStatuses: false,
canSendReminders: false,
refreshTrigger: 0
});
const emit = defineEmits<Emits>();
// State
const dismissed = ref(false);
const updatingStatuses = ref(false);
// Update overdue member statuses
const updateOverdueStatuses = async () => {
updatingStatuses.value = true;
try {
const response = await $fetch<{
success: boolean;
data: { updatedCount: number };
message?: string;
}>('/api/members/update-overdue-statuses', {
method: 'POST'
});
if (response.success) {
emit('statuses-updated', response.data.updatedCount);
console.log(`Updated ${response.data.updatedCount} overdue member statuses`);
} else {
throw new Error(response.message || 'Failed to update statuses');
}
} catch (error: any) {
console.error('Error updating overdue statuses:', error);
// Show error notification if needed
} finally {
updatingStatuses.value = false;
}
};
// Reset dismissed state when refresh trigger changes
watch(() => props.refreshTrigger, () => {
dismissed.value = false;
});
// Watch for overdueCount changes and reset dismissed
watch(() => props.overdueCount, (newCount, oldCount) => {
if (newCount > oldCount) {
dismissed.value = false;
}
});
</script>
<style scoped>
.dues-overdue-banner {
border-radius: 12px !important;
box-shadow: 0 4px 12px rgba(255, 152, 0, 0.2) !important;
}
.dues-overdue-banner :deep(.v-alert__content) {
width: 100%;
}
.gap-2 {
gap: 8px;
}
/* Mobile responsive */
@media (max-width: 600px) {
.d-flex.flex-wrap {
flex-direction: column;
align-items: stretch !important;
}
.d-flex.flex-wrap .v-btn {
margin-bottom: 8px;
}
.v-spacer {
display: none;
}
}
</style>