fixes
Build And Push Image / docker (push) Successful in 1m39s
Details
Build And Push Image / docker (push) Successful in 1m39s
Details
This commit is contained in:
parent
136eb5229e
commit
cdacb4a114
|
|
@ -98,34 +98,73 @@
|
|||
<!-- Mark as Paid Dialog -->
|
||||
<v-dialog v-model="markAsPaidDialog" max-width="400">
|
||||
<v-card>
|
||||
<v-card-title class="text-h6">
|
||||
<v-icon left color="success">mdi-check-circle</v-icon>
|
||||
<v-card-title class="text-h6 pa-4">
|
||||
<v-icon left color="success">mdi-calendar-check</v-icon>
|
||||
Mark Dues as Paid
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<p>Are you sure you want to mark the dues as paid for this member?</p>
|
||||
<p class="text-body-2 text-medium-emphasis">
|
||||
This will remove the payment banner and update the member's status.
|
||||
</p>
|
||||
<v-card-text class="pa-4">
|
||||
<div class="mb-4">
|
||||
<h4 class="text-subtitle-1 mb-2">
|
||||
{{ memberData?.FullName || `${memberData?.first_name || ''} ${memberData?.last_name || ''}`.trim() }}
|
||||
</h4>
|
||||
<p class="text-body-2 text-medium-emphasis">
|
||||
Select the date when the dues payment was received:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="date-picker-wrapper">
|
||||
<label class="date-picker-label">Payment Date</label>
|
||||
<VueDatePicker
|
||||
v-model="selectedPaymentModel"
|
||||
:timezone="{
|
||||
timezone: 'Europe/Monaco',
|
||||
emitTimezone: 'UTC'
|
||||
}"
|
||||
:format="'dd/MM/yyyy (Monaco)'"
|
||||
:max-date="new Date()"
|
||||
placeholder="Select payment date"
|
||||
:enable-time-picker="false"
|
||||
auto-apply
|
||||
:clearable="false"
|
||||
:required="true"
|
||||
@update:model-value="handleDateUpdate"
|
||||
/>
|
||||
<div class="text-caption text-medium-emphasis mt-1">
|
||||
Select the date when the payment was received
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-alert
|
||||
v-if="selectedPaymentDate && isDateInFuture"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
class="mt-2"
|
||||
density="compact"
|
||||
>
|
||||
<v-icon start>mdi-information</v-icon>
|
||||
Future dates are not allowed. Please select today or an earlier date.
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-card-actions class="pa-4 pt-0">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@click="markAsPaidDialog = false"
|
||||
@click="cancelPaymentDialog"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="flat"
|
||||
variant="elevated"
|
||||
:disabled="!selectedPaymentDate || isDateInFuture"
|
||||
:loading="updating"
|
||||
@click="markDuesAsPaid"
|
||||
>
|
||||
Mark as Paid
|
||||
<v-icon start>mdi-check-circle</v-icon>
|
||||
Confirm Payment
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
|
@ -172,6 +211,10 @@ const config = ref<RegistrationConfig>({
|
|||
accountHolder: ''
|
||||
});
|
||||
|
||||
// Reactive state for payment date dialog
|
||||
const selectedPaymentDate = ref('');
|
||||
const selectedPaymentModel = ref<Date | null>(null);
|
||||
|
||||
const snackbar = ref({
|
||||
show: false,
|
||||
message: '',
|
||||
|
|
@ -311,6 +354,21 @@ const paymentMessage = computed(() => {
|
|||
}
|
||||
});
|
||||
|
||||
const todayDate = computed(() => {
|
||||
return new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
|
||||
});
|
||||
|
||||
const isDateInFuture = computed(() => {
|
||||
if (!selectedPaymentDate.value) return false;
|
||||
|
||||
const selectedDate = new Date(selectedPaymentDate.value);
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0); // Reset time to start of day
|
||||
selectedDate.setHours(0, 0, 0, 0); // Reset time to start of day
|
||||
|
||||
return selectedDate > today;
|
||||
});
|
||||
|
||||
// Methods
|
||||
function dismissBanner() {
|
||||
dismissed.value = true;
|
||||
|
|
@ -325,30 +383,31 @@ function dismissBanner() {
|
|||
}
|
||||
|
||||
async function markDuesAsPaid() {
|
||||
if (!memberData.value?.Id) return;
|
||||
if (!memberData.value?.Id || !selectedPaymentDate.value || isDateInFuture.value) return;
|
||||
|
||||
updating.value = true;
|
||||
|
||||
try {
|
||||
// Update member's dues status
|
||||
// Update member's dues status with the selected payment date
|
||||
await $fetch(`/api/members/${memberData.value.Id}`, {
|
||||
method: 'PUT',
|
||||
body: {
|
||||
current_year_dues_paid: 'true',
|
||||
membership_date_paid: new Date().toISOString(),
|
||||
payment_due_date: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString() // Next year
|
||||
membership_date_paid: selectedPaymentDate.value,
|
||||
payment_due_date: new Date(new Date(selectedPaymentDate.value).getTime() + 365 * 24 * 60 * 60 * 1000).toISOString() // Next year from payment date
|
||||
}
|
||||
});
|
||||
|
||||
// Update local member state
|
||||
if (memberData.value) {
|
||||
memberData.value.current_year_dues_paid = 'true';
|
||||
memberData.value.membership_date_paid = new Date().toISOString();
|
||||
memberData.value.membership_date_paid = selectedPaymentDate.value;
|
||||
}
|
||||
|
||||
// Hide banner
|
||||
// Hide banner and reset
|
||||
showBanner.value = false;
|
||||
markAsPaidDialog.value = false;
|
||||
selectedPaymentDate.value = '';
|
||||
|
||||
// Show success message
|
||||
snackbar.value = {
|
||||
|
|
@ -369,6 +428,19 @@ async function markDuesAsPaid() {
|
|||
}
|
||||
}
|
||||
|
||||
// Date picker handler
|
||||
const handleDateUpdate = (date: Date | null) => {
|
||||
if (date) {
|
||||
selectedPaymentDate.value = date.toISOString().split('T')[0];
|
||||
}
|
||||
};
|
||||
|
||||
const cancelPaymentDialog = () => {
|
||||
markAsPaidDialog.value = false;
|
||||
selectedPaymentDate.value = '';
|
||||
selectedPaymentModel.value = null;
|
||||
};
|
||||
|
||||
// Load member data for the current user from session
|
||||
async function loadMemberData() {
|
||||
if (!user.value) return;
|
||||
|
|
@ -460,6 +532,76 @@ onMounted(() => {
|
|||
border: 1px solid rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
/* Date picker styling to match Vuetify */
|
||||
.date-picker-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.date-picker-label {
|
||||
font-size: 16px;
|
||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.009375em;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Style the Vue DatePicker to match Vuetify inputs */
|
||||
:deep(.dp__input) {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 4px;
|
||||
padding: 16px 12px;
|
||||
padding-right: 48px; /* Make room for calendar icon */
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
background: rgb(var(--v-theme-surface));
|
||||
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||
transition: border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
width: 100%;
|
||||
min-height: 56px;
|
||||
}
|
||||
|
||||
:deep(.dp__input:hover) {
|
||||
border-color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||
}
|
||||
|
||||
:deep(.dp__input:focus) {
|
||||
border-color: rgb(var(--v-theme-primary));
|
||||
border-width: 2px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
:deep(.dp__input_readonly) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Style the date picker dropdown */
|
||||
:deep(.dp__menu) {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
background: rgb(var(--v-theme-surface));
|
||||
}
|
||||
|
||||
/* Primary color theming for the date picker */
|
||||
:deep(.dp__primary_color) {
|
||||
background-color: rgb(var(--v-theme-primary));
|
||||
}
|
||||
|
||||
:deep(.dp__primary_text) {
|
||||
color: rgb(var(--v-theme-primary));
|
||||
}
|
||||
|
||||
:deep(.dp__active_date) {
|
||||
background-color: rgb(var(--v-theme-primary));
|
||||
color: rgb(var(--v-theme-on-primary));
|
||||
}
|
||||
|
||||
:deep(.dp__today) {
|
||||
border: 1px solid rgb(var(--v-theme-primary));
|
||||
}
|
||||
|
||||
/* Mobile responsiveness */
|
||||
@media (max-width: 600px) {
|
||||
.banner-content .text-h6 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue